一、什么是rpc?
简而言之,RPC就是一个本地程序可以通过网络调用远程的一个子程序。
二、Go语言的rpc
rpc分为server端和client端。server端即为服务端,即提供服务方,client端为调用端(客户端),即远程调用服务端一方。
实现一个RPC需要解决哪些问题
server端是服务提供方,client端是服务调用方。既然server端可以提供服务,那么它要先实现服务的注册,只有注册过的服务才能被client端调用。前文也说过,client端和server端一般不在一个进程内,甚至不在一个计算机内,那么他们之间的通信必然是通过网络传输,这样就涉及到了网络传输协议,说的更直白的,就是如何将client端的数据(一般是要调用的服务名和相应的参数)安全传输到server端,而server端也能完整的接收到。在client端和server端,数据一般是以对象的形式存在,而对象是无法进行网络传输的,在网络传输之前,我们需要先把对象序列化成字节流,然后传输这些字节流,server端在接收到这些字节流之后,再反序列化得到原始对象,这就是序列化与反序列化。
所以要实现一个rpc要考虑三个问题:
- 1、服务端注册
- 2、网络传输
- 3、序列化和反序列化
go语言自带的标准库中的/net/rpc 包可以帮助实现一个简单的rpc server端。以下是/net/rpc包的一些说明:
rpc包提供了通过网络或其他I/O连接对一个对象的导出方法的访问。服务端注册一个对象,使它作为一个服务被暴露,服务的名字是该对象的类型名。注册之后,对象的导出方法就可以被远程访问。服务端可以注册多个不同类型的对象(服务),但注册具有相同类型的多个对象是错误的。
只有满足如下标准的方法才能用于远程访问,其余方法会被忽略:
- 方法是导出的
- 方法有两个参数,都是导出类型或内建类型
- 方法的第二个参数是指针
- 方法只有一个error接口类型的返回值
事实上,方法必须看起来像这样:
func (t *T) MethodName(argType T1, replyType *T2) error
一个简单的rpc server端实现如下:
package main
import (
"log"
"net"
"net/rpc"
)
type Args struct {
A, B int
}
type Arith int
func (t *Arith) Multiply(args Args, reply *int) error {
*reply = args.A * args.B
return nil
}
func main() {
// 创建一个rpc server对象
newServer := rpc.NewServer()
// 向rpc server对象注册一个Arith对象,注册后,client就可以调用Arith的Multiply方法
arith := new(Arith)
newServer.Register(arith)
// 监听本机的1234端口
l, e := net.Listen("tcp", "127.0.0.1:1234")
if e != nil {
log.Fatalf("net.Listen tcp :0: %v", e)
}
for {
// 阻塞直到从1234端口收到一个网络连接
conn, e := l.Accept()
if e != nil {
log.Fatalf("l.Accept: %v", e)
}
//开始工作
go newServer.ServeConn(conn)
}
}
client端调用
package main
import (
"log"
"net"
"net/rpc"
)
type Args struct {
A, B int
}
func main() {
conn ,_:= net.Dial("tcp", ":1234")
defer conn.Close()
client := rpc.NewClient(conn)
defer client.Close()
args := Args{7,8}
var reply int
err := client.Call("Arith.Multiply", args, &reply)
if err != nil {
log.Fatal("arith error:", err)
}
log.Println(reply)
}
我们先连接本机的1234端口(这个端口server.go在监听),得到一个net.Conn对象,然后用这个对象new出来了一个rpc client,然后再通过这个client调用服务端提供的方法Multiply,计算完后把结果存到reply中。
输出结果:
关于rpc详细的说明可以参考这篇博客https://juejin.im/post/5a69e308518825733b0f151a