golang?RPC包原理和使用詳細介紹
本篇文章旨在通過學習rpc包和github上的一個rpc小項目,熟悉和學習golang中各個包的使用
工作流程
通過閱讀官方文檔,了解了rpc的基本工作模式
- 第一步,建立一個用于遠程調(diào)用的包,存放僅供遠程調(diào)用使用的方法和類型-
- 第二步,實例化包的對象,并在rpc中注冊該包,以便之后的調(diào)用
- 第三步,建立一個服務端,接收客戶端的請求,使用編碼器解析請求后,根據(jù)請求中的方法和參數(shù),調(diào)用第二步注冊的實例的方法,然后使用編碼器把返回值加密后,返回給客戶端
- 第四步,建立一個客戶端,連接服務端,成功后,向連接發(fā)送使用編碼器加密后的數(shù)據(jù),然后等待服務端響應(同步或異步)。響應成功后,使用編碼器解析服務端返回的數(shù)據(jù)
第三步第四步中,多次用到的編碼器,是rpc包的關(guān)鍵。默認情況下,rpc包使用的是go特有的encoding/gob包進行數(shù)據(jù)的編碼和解碼。但是當我們服務端和客戶端使用了不同的語言時,若加密方法無法兼容,就會出現(xiàn)問題,所以rpc包支持自定義編碼器。
工作模式
go的rpc除了支持常規(guī)常規(guī)的tpc+端口的遠程調(diào)用方式,也支持基于http的遠程調(diào)用實現(xiàn)。但是,我都用rpc了,還用個毛的http形式。不過作為一種形式,我們出于禮貌的簡單了解下。
http模式
官方文檔的例子,就是使用的http形式的rpc,如下
服務端
//實例化rpc遠程調(diào)用的方法所屬對象
arith := new(Arith)
//注冊對象
rpc.Register(arith)
//把rpc監(jiān)聽 對應到http處理器。即指定http請求addr+port時,調(diào)用的方法
rpc.HandleHTTP()
//獲取監(jiān)聽地址
l, e := net.Listen("tcp", ":1234")
if e != nil {
log.Fatal("listen error:", e)
}
//開啟一個go程,持續(xù)處理監(jiān)聽數(shù)據(jù)
go http.Serve(l, nil)
客戶端
//連接 rpc的http服務端
client, err := rpc.DialHTTP("tcp", serverAddress + ":1234")
if err != nil {
log.Fatal("dialing:", err)
}
//同步調(diào)用
// 實例化rpc傳入?yún)?shù)
args := &server.Args{7,8}
//聲明rpc 回復參數(shù)。傳入和回復參數(shù),必須與調(diào)用方法中的參入類型一致
var reply int
//調(diào)用rpc注冊的方法
err = client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
fmt.Printf("Arith: %d*%d=%d", args.A, args.B, reply)
//或:異步調(diào)用
// Asynchronous call
quotient := new(Quotient)
divCall := client.Go("Arith.Divide", args, quotient, nil)
replyCall := <-divCall.Done // will be equal to divCall從上面的代碼可以看到,請求服務端時,需要客戶端在服務器發(fā)起http請求,如果直接在瀏覽器或者其他工具發(fā)起http請求則報錯,因為此時rpc.HandleHTTP方法指定的默認方法,使用的是默認gob編碼器,且只接收connect類型的請求。查看源代碼,如下

直接發(fā)起的http請求,無法使用go獨有的gob包編碼,rpc服務端也就無法使用默認gob包解碼。
所以我們要寫一個新的方法代替rpc.HandleHTTp,把http請求綁定到一個使用其他解碼器的方法上,如下
//注冊路由和對應的handler
http.HandleFunc("/json", func(rw http.ResponseWriter, r *http.Request) {
//聲明一個客戶端連接對象
var conn io.ReadWriteCloser = struct {
io.Writer
io.ReadCloser
}{
ReadCloser: r.Body,
Writer: rw,
}
//也可以使用如下方法獲取接管客戶端連接,http處理器不在管理該鏈接,使用完畢后需要自行關(guān)閉鏈接
// conn, _, err := rw.(http.Hijacker).Hijack()
// if err != nil {
// log.Print("rpc hijacking fail: ", err.Error())
// return
// }
io.WriteString(conn, "HTTP/1.0 rpc-ok\n\n")
//server.ServeConn(conn)
//rpc.ServeRequest,指定編碼器,以同步的方式處理請求一次,編碼器內(nèi)不關(guān)閉鏈接,由http服務處理。適用于http形式的請求,因為http是無狀態(tài)的,每次請求都是一個新的鏈接
//rpc.ServeCodec,指定編碼器,for循環(huán)接收客戶端鏈接的消息,每次消息處理開啟一個go程,相當于異步處理,直到客戶端關(guān)閉或解碼錯誤,跳出循環(huán),關(guān)閉連接。適用客戶端,一次連接多次發(fā)送數(shù)據(jù)
rpc.ServeRequest(jsonrpc.NewServerCodec(conn))})
//監(jiān)聽http請求
http.ListenAndServe("127.0.0.1:1234", nil)
上面代碼中的==jsonrpc.NewServerCodec(conn)==是一個官方定義好的json格式的編碼器。我們在http中發(fā)送數(shù)據(jù)時,只要使用json格式,就能被服務端解析
執(zhí)行g(shù)o文件,在post模擬url請求,如下

服務器模式
服務端
//聲明和注冊rpc方法對象
//獲取監(jiān)聽信息
lis, err := net.Listen("tcp", ":8082")
if err != nil {
log.Fatal(err)
}
//循環(huán)讀取監(jiān)聽到的數(shù)據(jù)
for {
//獲取一個客戶端連接
conn, err := lis.Accept()
if err != nil {
continue
}
//開啟一個go程序,使用自定義編碼器處理當前獲取連接
go s.Server.ServeCodec(jsonrpc.NewServerCodec(conn))
}
客戶端
//連接服務端
conn, err := net.Dial("tcp", ":8082")if err != nil {
log.Fatal(err)
}
defer conn.Close()
//使用json編碼器新建客戶端
client := &Client{rpc.NewClientWithCodec(jsonrpc.NewServerCodec(conn))}
//聲明rpc方法中傳入和輸出的參數(shù)
resq := message.ArithRequest{A: 20, B: 5}
resp := message.ArithResponse{}
//調(diào)用rpc方法
err = client.Call("ArithService.Add", &resq, &resp)
log.Printf("Arith.Add(%v, %v): %v ,Error: %v", resq.A, resq.B, resp.C, err)
到此這篇關(guān)于golang RPC包原理和使用詳細介紹的文章就介紹到這了,更多相關(guān)golang RPC包內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于go平滑重啟庫overseer實現(xiàn)原理詳解
這篇文章主要為大家詳細介紹了關(guān)于go平滑重啟庫overseer實現(xiàn)原理,文中的示例代碼講解詳細,具有一定的參考價值,有需要的小伙伴可以參考下2023-11-11
golang?pprof監(jiān)控memory?block?mutex使用指南
這篇文章主要為大家介紹了golang?pprof監(jiān)控memory?block?mutex使用指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-04-04
Go 1.23中Timer無buffer的實現(xiàn)方式詳解
在 Go 1.23 中,Timer 的實現(xiàn)通常是通過 time 包提供的 time.Timer 類型來實現(xiàn)的,本文主要介紹了Go 1.23中Timer無buffer的實現(xiàn)方式,需要的可以了解下2025-03-03
關(guān)于golang高并發(fā)的實現(xiàn)與注意事項說明
這篇文章主要介紹了關(guān)于golang高并發(fā)的實現(xiàn)與注意事項說明,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-05-05

