go語言rpc學習
rpc 就是 遠端過程呼叫 指的是呼叫遠端伺服器上的程式的方法整個過程。
rpc 理論
RPC技術在架構設計上有四部分組成,分別是:客戶端、客戶端存根、服務端、服務端存根。
客戶端:服務呼叫發起方 又叫做 服務消費者
伺服器: server上執行的可以被客戶端呼叫的方法
客戶端存根:存放server端的地址和埠訊息 。 將客戶端訊息打包轉換成網路訊息 傳送給服務端 。 接受服務端的資料包 該程式執行在客戶端。
服務端存根:存放client 網路資料 解析資料 呼叫本地對應的方法執行,將產生的結果回給客戶端 該程式執行在 服務端。
go語言自帶的rpc 框架的使用
1 服務定義及暴露
在程式設計實現過程中,伺服器端需要註冊結構體物件,然後通過物件所屬的方法暴露給呼叫者,從而提供服務,該方法稱之為輸出方法,此輸出方法可以被遠端呼叫。
當然,在定義輸出方法時,能夠被遠端呼叫的方法需要遵循一定的規則。我們通過程式碼進行講解:
func (t *T) MethodName(request T1,response *T2) error
上述程式碼是go語言官方給出的對外暴露的服務方法的定義標準,其中包含了主要的幾條規則,分別是:
- 1、對外暴露的方法有且只能有兩個引數,這個兩個引數只能是輸出型別或內建型別,兩種型別中的一種。
- 2、方法的第二個引數必須是指標型別。
- 3、方法的返回型別為error。
- 4、方法的型別是可輸出的。
- 5、方法本身也是可輸出的。
我們舉例說明:假設目前我們有一個需求,給出一個float型別變數,作為圓形的半徑,要求通過RPC呼叫,返回對應的圓形面積。具體的程式設計實現思路如下:
type MathUtil struct{
}
//該方法向外暴露:提供計算圓形面積的服務
func (mu *MathUtil) CalculateCircleArea(req float32, resp *float32) error {
*resp = math.Pi * req * req //圓形的面積 s = π * r * r
return nil //返回型別
}
在上述的案例中,我們可以看到:
- 1、Calculate方法是服務物件MathUtil向外提供的服務方法,該方法用於接收傳入的圓形半徑資料,計算圓形面積並返回。
- 2、第一個引數req代表的是呼叫者(client)傳遞提供的引數。
- 3、第二個引數resp代表要返回給呼叫者的計算結果,必須是指標型別。
- 4、正常情況下,方法的返回值為是error,為nil。如果遇到異常或特殊情況,則error將作為一個字串返回給呼叫者,此時,resp引數就不會再返回給呼叫者。
至此為止,已經實現了服務端的功能定義,接下來就是讓服務程式碼生效,需要將服務進行註冊,並啟動請求處理。
2 註冊服務及監聽請求
net/rpc包為我們提供了註冊服務和處理請求的一系列方法,結合本案例實現註冊及處理邏輯,如下所示:
//1、初始化指標資料型別
mathUtil := new(MathUtil) //初始化指標資料型別
//2、呼叫net/rpc包的功能將服務物件進行註冊
err := rpc.Register(mathUtil)
if err != nil {
panic(err.Error())
}
//3、通過該函式把mathUtil中提供的服務註冊到HTTP協議上,方便呼叫者可以利用http的方式進行資料傳遞
rpc.HandleHTTP()
//4、在特定的埠進行監聽
listen, err := net.Listen("tcp", ":8081")
if err != nil {
panic(err.Error())
}
go http.Serve(listen, nil)
經過服務註冊和監聽處理,RPC呼叫過程中的服務端實現就已經完成了。接下來需要實現的是客戶端請求程式碼的實現。
3 客戶端呼叫
在服務端是通過Http的埠監聽方式等待連線的,因此在客戶端就需要通過http連線,首先與服務端實現連線。
-
客戶端連線服務端
client, err := rpc.DialHTTP("tcp", "localhost:8081") if err != nil { panic(err.Error()) }
-
遠端方法呼叫 客戶端成功連線服務端以後,就可以通過方法呼叫呼叫服務端的方法,具體呼叫方法如下:
var req float32 //請求值 req = 3 var resp *float32 //返回值 err = client.Call("MathUtil.CalculateCircleArea", req, &resp) if err != nil { panic(err.Error()) } fmt.Println(*resp)
上述的呼叫方法核心在於client.Call方法的呼叫,該方法有三個引數,
-
第一個引數表示要呼叫的遠端服務的方法名,第二個引數是呼叫時要傳入的引數,第三個引數是呼叫要接收的返回值。 上述的Call方法呼叫實現的方式是同步的呼叫,除此之外,還有一種非同步的方式可以實現呼叫。非同步呼叫程式碼實現如下:
-
var respSync *float32 //非同步的呼叫方式 syncCall := client.Go("MathUtil.CalculateCircleArea", req, &respSync, nil) replayDone := <-syncCall.Done fmt.Println(replayDone) fmt.Println(*respSync)
4 多引數的請求呼叫引數傳遞
上述內容演示了單個引數下的RPC呼叫,對於多引數下的請求該如何實現。我們通過另外一個案例進行演示。
假設現在需要實現另外一個需求:通過RPC呼叫實現計算兩個數字相加功能並返回計算結果。此時,就需要傳遞兩個引數,具體實現如下:
將引數定義在一個新的結構體中,存放在param包中:
type AddParma struct {
Args1 float32 //第一個引數
Args2 float32 //第二個引數
}
在server.go檔案中,實現兩數相加的功能,並實現服務註冊的邏輯:
func (mu *MathUtil) Add(param param.AddParma, resp *float32) error {
*resp = param.Args1 + param.Args2 //實現兩數相加的功能
return nil
}
mathUtil := new(MathUtil)
err := rpc.RegisterName("MathUtil", mathUtil)//多引數的呼叫 設定方法就在這裡調整的 對比下上面的 單個引數的註冊區別
if err != nil {
panic(err.Error())
}
rpc.HandleHTTP()
listen, err := net.Listen("tcp", ":8082")
http.Serve(listen, nil)
在本案例中,我們通過新的註冊方法rpc.RegisterName實現了服務的註冊和呼叫。
至此,我們已經完成了net/rpc包的最基礎的使用。
https://github.com/rubyhan1314/Golang-100-Days/tree/master/Day80(RPC%E8%BF%9C%E7%A8%8B%E8%B0%83%E7%94%A8%E6%9C%BA%E5%88%B6)/code
上面的連線對應三個例子 程式碼對應三個 一個是單個 引數 一個是多個引數 一個就是prob 封裝的引數 環境安裝啃爹 prob go語言到環境到 protobuf構建有點麻煩