使用golang 實現JSON RPC2 0

2021-09-13 18:30:45 字數 4698 閱讀 8248

本文同時發布於我的部落格

yeqown.github.io

遠端過程呼叫(英語:remote procedure call,縮寫為 rpc)是乙個計算機通訊協議。該協議允許執行於一台計算機的程式呼叫另一台計算機的子程式,而程式設計師無需額外地為這個互動作用程式設計。如果涉及的軟體採用物件導向程式設計,那麼遠端過程呼叫亦可稱作遠端呼叫或遠端方法呼叫。

遠端過程呼叫是乙個分布式計算的客戶端-伺服器(client/server)的例子,它簡單而又廣受歡迎。遠端過程呼叫總是由客戶端對伺服器發出乙個執行若干過程請求,並用客戶端提供的引數。執行結果將返回給客戶端。由於存在各式各樣的變體和細節差異,對應地派生了各式遠端過程呼叫協議,而且它們並不互相相容。

json-rpc,是乙個無狀態且輕量級的遠端過程呼叫(rpc)傳送協議,其傳遞內容通過 json 為主。相較於一般的 rest 通過**(如 get /user)呼叫遠端伺服器,json-rpc 直接在內容中定義了欲呼叫的函式名稱(如 ),這也令開發者不會陷於該使用 put 或者 patch 的問題之中。

更多json-rpc約定參見:

服務端註冊及呼叫

約定如net/rpc

// 這就是約定

func (t *t) methodname(argtype t1, replytype *t2) error

那麼問題來了:

問題1: server怎麼來註冊`t.methods`?

問題2: json-rpc請求引數裡面的params給到args?

server端型別定義:

type methodtype struct 

type service struct

// server represents an rpc server.

type server struct

// 解析傳入的型別及相應的可匯出方法,將rcvr的type,methods的相關資訊存放到server.m中。

// 如果type是不可匯出的,則會報錯

func (s *server) register(rcvr inte***ce{}) error

if !i***ported(sname)

_service.name = sname

_service.method = suitablemethods(_service.typ, true)

// sync.map.loadorstore

if _, dup := s.m.loadorstore(sname, _service); dup

return nil

}// 關於suitablemethods,也是使用reflect,

// 來獲取_service.typ中的所有可匯出方法及方法的相關引數,儲存成*methodtype

suitablemethods**由此去:https:

解決問題2,要解決問題2,且先看如何呼叫method,**如下:

// 約定:    func (t *t) methodname(argtype t1, replytype *t2) error

// s.rcvr: 即約定中的 t

// ar**: 即約定中的 argtype

// replyv: 即約定中的 replytype

func (s *service) call(mtype *methodtype, req *request, ar**, replyv reflect.value) *response )

erriter := returnvalues[0].inte***ce()

errmsg := ""

if erriter != nil

return newresponse(req.id, replyv.inte***ce(), nil)

}

看了如何呼叫,再加上json-rpc的約定,知道了傳給服務端的是乙個json,而且其中的params是乙個json格式的資料。那就變成了:inte***ce{}- req.params 到reflect.value- ar**。那麼怎麼轉換呢?看**:

func (s *server) call(req *request) *response  else 

if argisvalue

// 為ar**引數生成了乙個reflect.value,但是ar**目前為止都還是是0值。

// 那麼怎麼把req.params 複製給ar** ?

// 我嘗試過,ar** = reflect.value(req.params),但是在呼叫的時候 會提示說:「map[string]inte***ce{} as main.*args」,

// 這也就是說,並沒有將引數的值正確的賦值給ar**。

// 後面才又了這個convert函式:

// bs, _ := json.marshal(req.params)

// json.unmarshal(bs, ar**.inte***ce())

// 因此有一些限制~,就不多說了

convert(req.params, ar**.inte***ce())

// note: 約定中replytype是乙個指標型別,方便賦值。

// 根據註冊時候的mtype.replytype來生成乙個reflect.value

replyv := reflect.new(mtype.replytype.elem())

switch mtype.replytype.elem().kind()

return svc.call(mtype, req, ar**, replyv)

}

支援http呼叫

已經完成了上述的部分,再來談支援http就非常簡單了。實現http.handler介面就行啦~。如下:

// 支援之post & json

// 解析請求引數到*rpc.request

reqs, err := getrequestfrombody(r)

if err != nil

// 處理請求,包括批量請求

resps := s.handlewithrequests(reqs)

if len(resps) > 1 else

return

}

服務端使用
// test_server.go

客戶端使用
// test_client.go

}

執行截圖

只支援json-rpc, 且還沒有完全實現json-rpc的約定。譬如批量呼叫中:

若批量呼叫的 rpc 操作本身非乙個有效 json 或乙個至少包含乙個值的陣列,則服務端返回的將單單是乙個響應物件而非陣列。若批量呼叫沒有需要返回的響應物件,則服務端不需要返回任何結果且必須不能返回乙個空陣列給客戶端。
閱讀參考中的兩個rpc,發現兩者都是使用的codec的方式來提供擴充套件。因此以後可以考慮使用這種方式來擴充套件。

Golang使用sort介面實現排序

為實現對自定義的struct進行排序,可以呼叫sort包中的sort方法,為此,自定義的struct集合需要實現len less swap 三項方法。官方文件中的描述為 func sort data inte ce sort排序data。它呼叫1次data.len確定長度,呼叫o n log n 次...

golang使用aes庫實現加解密

golang實現加密解密的庫很多,這裡使用的是aes庫 base64庫來實現.使用時,需要指定乙個私鑰,來進行加解密,這裡指定是 var aeskey byte 321423u9y8d2fwfl 上 package main import fmt crypto cipher crypto aes b...

golang 使用組合的方式實現繼承

火頭陀 關注 golang並非完全物件導向的程式語言,為了實現物件導向的繼承這一神奇的功能,golang允許struct間使用匿名引入的方式實現物件屬性方法的組合 package main import fmt type people struct type people2 struct func ...