RPC
RPC(Remote Procedure Call)远程过程调用在分布式技术中常常用到例如Hyperledger Fabric中内部节点通信就用到了RPC,还有如今流行的微服务架构在内部模块的沟通之间也常常使用RPC进行通信。
简单理解就是,本地机器调用远端服务机器上的方法,向远端机器指明要调用的方法、传入参数并拿回执行的结果。
Golang中的RPC
”
golang的RPC支持三个级别的RPC:TCP、HTTP、JSONRPC。但Go的RPC包是独一无二的RPC,它和传统的RPC系统不同,它只支持Go开发的服务器与客户端之间的交互,因为在内部,它们采用了Gob来编码。
Go RPC的函数只有符合下面的条件才能被远程访问,不然会被忽略,详细的要求如下:
-
函数必须是导出的(首字母大写)。
-
必须有两个导出类型的参数:
1)第一个参数是接收的参数,
2)第二个参数是返回给客户端的参数
*result
,它必须是指针类型的。 -
函数要返回一个
error
。 -
调用方法通常为:
Service.Method
。
“
来源:
Demo
首先,假设函数func (DemoService) Div(args Args, result *float64) error {...}
是我们需要调用的服务器上的函数,它的具体内容如下:
// rpcdemo/rpc.go
package rpcdemo
import "errors"
type DemoService struct {
}
// Args 由于有两个参数,所以构造一个 struct 作为参数
type Args struct {
A, B int
}
// Div 调用 rpc 时, 使用 Service.Method,也就是 DemoService.Div
func (DemoService) Div(args Args, result *float64) error {
if args.B == 0 {
return errors.New("division by zero")
}
*result = float64(args.A) / float64(args.B)
return nil
}
然后,在服务端注册该方法后,设置服务器监听请求的端口,连接到客户端后使用goroutine
处理:
// rpcdemo/server/serverRpc.go
package main
import (
"rpcdemo"
"fmt"
"log"
"net"
"net/rpc"
"net/rpc/jsonrpc"
)
func main() {
// 向 rpc 注册服务
rpc.Register(rpcdemo.DemoService{})
// 设置服务端监听端口
listener, err := net.Listen("tcp", ":1234")
if err != nil {
panic(err)
}
fmt.Println("Open serverRcp, listening on Port 1234...")
for {
// 监听端口到来的连接
conn, err := listener.Accept()
if err != nil {
log.Printf("accept error: %v", err)
}
fmt.Println("Get request from client...")
go func() {
jsonrpc.ServeConn(conn) // 开一个 goroutine 去做事情,这样还能继续接收别的连接
}()
}
}
让客户端连接相应的端口,发送请求并展示结果:
// rpcdemo/client/clientRpc.go
package main
import (
"rpcdemo"
"fmt"
"net"
"net/rpc/jsonrpc"
)
func main() {
// 首先客户端去连接端口
conn, err := net.Dial("tcp", ":1234")
if err != nil {
panic(err)
}
// 告诉客户端使用该链接
client := jsonrpc.NewClient(conn)
// 调用服务器上的方法
var result float64
err = client.Call("DemoService.Div", rpcdemo.Args{10, 3}, &result)
fmt.Println(result, err)
err = client.Call("DemoService.Div", rpcdemo.Args{10, 0}, &result)
fmt.Println(result, err)
}
依次运行服务器,客户端:
s1-> go run rpcdemo/server/serverRpc.go
----------------------------------
s2-> Open serverRcp, listening on Port 1234...
s4-> Get request from client...
==================================
s3-> go run rpcdemo/client/clientRpc.go
----------------------------------
s5-> 3.3333333333333335 <nil>
s6-> 3.3333333333333335 division by zero