本文同時發布於我的部落格遠端過程呼叫(英語:remote procedure call,縮寫為 rpc)是乙個計算機通訊協議。該協議允許執行於一台計算機的程式呼叫另一台計算機的子程式,而程式設計師無需額外地為這個互動作用程式設計。如果涉及的軟體採用物件導向程式設計,那麼遠端過程呼叫亦可稱作遠端呼叫或遠端方法呼叫。yeqown.github.io
遠端過程呼叫是乙個分布式計算的客戶端-伺服器(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 ...