golang對prc進行了支持,使用時只需要導入net/rpc的包即可:
import "net/rpc"
rpc包提供了通過網絡或其他I/O連接對一個對象的導出方法的訪問。服務端註冊一個對象,使它作爲一個服務被暴露,服務的名字是該對象的類型名。註冊之後,對象的導出方法就可以被遠程訪問。服務端可以註冊多個不同類型的對象(服務),但註冊具有相同類型的多個對象是錯誤的。
只有滿足如下標準的方法才能用於遠程訪問,其餘方法會被忽略:
- 方法是導出的
- 方法有兩個參數,都是導出類型或內建類型
- 方法的第二個參數是指針
- 方法只有一個error接口類型的返回值
事實上,方法必須看起來像這樣:
func (t *T) MethodName(argType T1, replyType *T2) error
其中T、T1和T2都能被encoding/gob包序列化。這些限制即使使用不同的編解碼器也適用。(未來,對定製的編解碼器可能會使用較寬鬆一點的限制)
方法的第一個參數代表 調用者提供的參數 ;第二個參數代表 返回給調用者的參數 。方法的返回值,如果非nil,將被作爲字符串回傳,在客戶端看來就和errors.New創建的一樣。如果返回了錯誤,回覆的參數將不會被髮送給客戶端。
服務端可能會單個連接上調用ServeConn管理請求。更典型地,它會創建一個網絡監聽器然後調用Accept;或者,對於HTTP監聽器,調用HandleHTTP和http.Serve。
想要使用服務的客戶端會創建一個連接,然後用該連接調用NewClient。
更方便的函數Dial(DialHTTP)會在一個原始的連接(或HTTP連接)上依次執行這兩個步驟。
生成的Client類型值有兩個方法,Call和Go,它們的參數爲要調用的服務和方法、一個包含參數的指針、一個用於接收接個的指針。
Call方法會等待遠端調用完成,而Go方法異步的發送調用請求並使用返回的Call結構體類型的Done通道字段傳遞完成信號。
除非設置了顯式的編解碼器,本包默認使用encoding/gob包來傳輸數據。
執行以下前提:安裝配置好golang開發環境
1.服務端
1.編輯服務端代碼
mkdir -p $GOPATH/src/rpctest/ && cd $_ && go mod init rpctest && mkdir -p srv && cd $_ && vim main.go
內容如下:
package main
import (
"log"
"net"
"net/http"
"net/rpc"
)
type Rpc struct {
}
/*
- 方法是導出的
- 方法有兩個參數,都是導出類型或內建類型
- 方法的第二個參數是指針
- 方法只有一個error接口類型的返回值
func (t *T) MethodName(argType T1, replyType *T2) error
*/
func (r *Rpc) GetSum(argType int, replyType *int) error {
*replyType = argType + 100
return nil
}
func main() {
// 1.結構體實例化
rp := new(Rpc)
// 2.rpc註冊
rpc.Register(rp)
// 3.rpc網絡
rpc.HandleHTTP()
// 4.監聽網絡
ln, err := net.Listen("tcp", "127.0.0.1:8899")
if err != nil {
log.Fatal(err)
}
// 5.等待網絡連接
http.Serve(ln, nil)
}
2.開啓服務端
cd $GOPATH/src/rpctest/srv && go run main.go
2.客戶端
1.編輯客戶端代碼
再開一個終端執行客戶端的操作,不要關閉服務端
mkdir -p $GOPATH/src/rpctest/ && cd $_ && mkdir -p cli && cd $_ && vim main.go
內容如下:
package main
import (
"log"
"net/rpc"
)
func main() {
// 1.連接服務器
cli, err := rpc.DialHTTP("tcp", "127.0.0.1:8899")
if err != nil {
log.Fatal(err)
}
// 2.調用函數
// serviceMethod :服務方法名,是一個 [ 結構體.方法名 ] 的字符串
// args :需要傳入的參數
// reply : 接收的變量參數
//func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error
var reply int
err = cli.Call("Rpc.GetSum", 99, &reply)
if err != nil {
log.Fatal(err)
}
// 3.打印結果
log.Println(reply)
}
2.執行客戶端
前提:保證服務端已經開啓
cd $GOPATH/src/rpctest/cli && go run main.go