RPC 編程 -二-: 快速入門使用
- 介紹
Go
語言標準包 (net/rpc
) 已經提供了對RPC
的支持,而且支持三個級別的 RPC:TCP、HTTP和JSONRPC
。但Go
語言的RPC
包是獨一無二的RPC
,它和傳統的 RPC 系統不同,它只支持 Go 語言開發的服務器與客戶端之間的交互,因爲在內部,它們採用了Gob
來編碼。
廢話不多說, 下面會分別實現: TCP版、HTTP版、JSONRPC版
的 RPC。開始擼代碼~~
2.TCP 版
Go 語言的 RPC 規則:方法只能有兩個可序列化的參數,其中第二個參數是指針類型,並且返回一個 error 類型,同時必須是公開的方法。
2.1 服務端實現
package main
import (
"log"
"net"
"net/rpc"
"time"
)
type HelloService struct{}
func (h *HelloService) Say(request string, response *string) error {
format := time.Now().Format("2006-01-02 15:04:05")
*response = request + " -- " + format
return nil
}
func main() {
// 註冊服務名稱
_ = rpc.RegisterName("HelloService", new(HelloService))
// 監聽端口
listen, err := net.Listen("tcp", ":1234")
if err != nil {
return
}
for {
// 監聽請求
accept, err := listen.Accept()
if err != nil {
log.Fatalf("Accept Error: %s", err)
}
go rpc.ServeConn(accept)
}
}
rpc.RegisterName()
函數調用會將對象類型中所有滿足 RPC 規則的對象方法註冊爲 RPC 函數,所有註冊的方法會放在HelloService
服務的空間之下。然後建立一個唯一的 TCP 鏈接,並且通過rpc.ServeConn()
函數在該 TCP 鏈接上爲對方提供 RPC 服務。
2.2 客戶端實現
package main
import (
"fmt"
"log"
"net/rpc"
"time"
)
func main() {
// 建立鏈接
dial, err := rpc.Dial("tcp", "127.0.0.1:1234")
if err != nil {
log.Fatal("Dial error ", err)
}
var result string
for i := 0; i < 5; i++ {
// 發起請求
_ = dial.Call("HelloService.Say", "go", &result)
fmt.Println("result:", result)
time.Sleep(time.Second * 2)
}
}
首先是通過rpc.Dial
撥號RPC
服務,然後通過client.Call()
調用具體的RPC
方法。在調用client.Call()
時,第一個參數是用點號鏈接的RPC
服務名字和方法名字,第二個和第三個參數分別是定義 RPC 方法的兩個參數。
2.3 啓動 & 請求
# 啓動服務
➜ go run rpc/server/main.go
# 啓動客戶端
➜ go run rpc/client/main.go
result: go -- 2022-01-08 21:42:18
result: go -- 2022-01-08 21:42:21
result: go -- 2022-01-08 21:42:23
result: go -- 2022-01-08 21:42:25
result: go -- 2022-01-08 21:42:27
- HTTP 版
3.1 服務端實現
package main
import (
"fmt"
"net/http"
"net/rpc"
)
type MathService struct {
}
// 相乘方法
func (u *MathService) Multi(a int, sum *int) error {
*sum = a * a
return nil
}
func main() {
userService := new(MathService)
// 註冊服務
err := rpc.Register(userService)
if err != nil {
return
}
rpc.HandleHTTP()
err = http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
3.2 客戶端實現
package main
import (
"fmt"
"net/rpc"
)
func main() {
// 建立鏈接
client, err := rpc.DialHTTP("tcp", ":8080")
if err != nil {
fmt.Println("err ", err)
return
}
// 返回
var result int
// 請求方法
for i := 1; i < 10; i++ {
err = client.Call("MathService.Multi", i, &result)
fmt.Printf("i:%v result:%v \n", i, result)
}
}
3.3 啓動 & 請求
# 啓動服務端
➜ go run rpc/http/server.go
# 啓動客戶端
➜ go run rpc/http/client.go
i:1 result:1
i:2 result:4
i:3 result:9
i:4 result:16
i:5 result:25
i:6 result:36
i:7 result:49
i:8 result:64
i:9 result:81
- JSON RPC
上面TCP版
和HTTP版
, 數據編碼採用的都是默認的gob
編碼,而gob
編碼是Go
特有的編碼和解碼的專用序列化方法,這也就意味着Gob
無法跨語言使用。而JSON RPC
則可以跨語言使用。
4.1 服務端實現
package main
import (
"52lu/go-study-example/rpc/jsonrpc/dto"
"fmt"
"net"
"net/rpc"
"net/rpc/jsonrpc"
"time"
)
type MathService struct {
}
// 求和
func (m MathService) Sum(arg *dto.SumParam, res *dto.SumRes) error {
fmt.Printf("arg: %#v\n", arg)
*res = dto.SumRes{
Sum: arg.A + arg.B,
Time: time.Now(),
}
return nil
}
func main() {
// 註冊服務
err := rpc.RegisterName("MathService", new(MathService))
if err != nil {
fmt.Println("rpc RegisterName err ", err)
return
}
// 監聽端口
listen, err := net.Listen("tcp", ":9090")
if err != nil {
fmt.Println("Listen err ", err)
return
}
// 監聽
for {
conn, err := listen.Accept()
if err != nil {
fmt.Println("conn err ", err)
return
}
// 使用json編碼
go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
}
}
4.2 客戶端實現
package main
import (
"52lu/go-study-example/rpc/jsonrpc/dto"
"fmt"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func main() {
// 建立鏈接
conn, err := net.Dial("tcp", ":9090")
if err != nil {
fmt.Println(" rpc.Dial err ", err)
return
}
// 使用json編碼
client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
// 參數
arg := dto.SumParam{A: 20, B: 80}
// 結果
var sum dto.SumRes
err = client.Call("MathService.Sum", &arg, &sum)
if err != nil {
fmt.Println("client.Call err ", err)
return
}
fmt.Printf("res:%+v \n", sum)
}
4.3 啓動 & 請求
# 啓動服務端
➜ go run rpc/jsonrpc/server.go
arg: &dto.SumParam{A:20, B:80} # 請求時打印
# 啓動客戶端
➜ go run rpc/jsonrpc/client.go
res:{Sum:100 Time:2022-01-10 23:12:48.880364 +0800 CST}
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/5RSkC4mM0q2ulP5VzOplgw