Golang RPC的原理与简单调用详解
作者:胡安民
RPC(Remote Procedure Call),主要是帮助我们屏蔽网络编程细节 ,是我们更专注于业务逻辑,实现调用远程方法就像调用本地方法一样。
RPC通信过程
由服务提供者给出业务接口声明,在调用方的程序里面,RPC 框架根据调用的服务接口提前生成动态代理实现类,并通过依赖注入等技术注入到声明了该接口的相关业务逻辑里面。该代理实现类会拦截所有的方法调用,在提供的方法处理逻辑里面完成一整套的远程调用,并把远程调用结果返回给调用方,这样调用方在调用远程方法的时候就获得了像调用本地接口一样的体验。
RPC设计组成
以下是对RPC的四种角色的解释和说明:
客户端(Client): 服务调用发起方,也称为服务消费者。
客户端存根(Client Stub): 该程序运行在客户端所在的计算机机器上,主要用来存储要调用的服务器的地址,另外,该程序还负责将客户端请求远端服务器程序的数据信息打包成数据包,通过网络发送给服务端Stub程序;其次,还要接收服务端Stub程序发送的调用结果数据包,并解析返回给客户端。
服务端(Server): 远端的计算机机器上运行的程序,其中有客户端要调用的方法。
服务端存根(Server Stub): 接收客户Stub程序通过网络发送的请求消息数据包,并调用服务端中真正的程序功能方法,完成功能调用;其次,将服务端执行调用的结果进行数据处理打包发送给客户端Stub程序。
RPC原理和调用步骤
实际上,如果我们想要在网络中的任意两台计算机上实现远程调用过程,要解决很多问题,比如:
- 两台物理机器在网络中要建立稳定可靠的通信连接。
- 两台服务器的通信协议的定义问题,即两台服务器上的程序如何识别对方的请求和返回结果。也就是说两台计算机必须都能够识别对方发来的信息,并且能够识别出其中的请求含义和返回含义,然后才能进行处理。这其实就是通信协议所要完成的工作。
我们来看看RPC具体是如何解决这些问题的,RPC具体的调用步骤图如下:
在上述图中,通过1-10的步骤图解的形式,说明了RPC每一步的调用过程。具体描述为:
1、客户端想要发起一个远程过程调用,首先通过调用本地客户端Stub程序的方式调用想要使用的功能方法名;
2、客户端Stub程序接收到了客户端的功能调用请求,将客户端请求调用的方法名,携带的参数等信息做序列化操作,并打包成数据包。
3、客户端Stub查找到远程服务器程序的IP地址,调用Socket通信协议,通过网络发送给服务端。
4、服务端Stub程序接收到客户端发送的数据包信息,并通过约定好的协议将数据进行反序列化,得到请求的方法名和请求参数等信息。
5、服务端Stub程序准备相关数据,调用本地Server对应的功能方法进行,并传入相应的参数,进行业务处理。
6、服务端程序根据已有业务逻辑执行调用过程,待业务执行结束,将执行结果返回给服务端Stub程序。
7、服务端Stub程序将程序调用结果按照约定的协议进行序列化, 并通过网络发送回客户端Stub程序。
8、客户端Stub程序接收到服务端Stub发送的返回数据,对数据进行反序列化操作, 并将调用返回的数据传递给客户端请求发起者。
9、客户端请求发起者得到调用结果,整个RPC调用过程结束。
简单的使用
在对RPC进行简单介绍之后,我们先看一个简单的RPC服务注册和调用的demo,
服务端代码如下:
package main import ( "fmt" "log" "net" "net/rpc" ) type HelloService struct{} func (p *HelloService) Hello(request string, reply *string) error { *reply = "hello:" + request log.Println("got req", request) return nil } func main() { // 创建TCP服务器 listener, err := net.Listen("tcp", ":8888") if err != nil { fmt.Println("Listen error:", err) return } // 创建RPC服务 rpcServer := rpc.NewServer() // 注册RPC服务(可以注册多个) rpcServer.RegisterName("HelloService", new(HelloService)) // 开始接收RPC请求 rpcServer.Accept(listener) }
客户端代码如下:
package main import ( "fmt" "log" "net/rpc" ) func main() { //访问rpc服务端 client, err := rpc.Dial("tcp", "localhost:8888") if err != nil { log.Fatal("dialing:", err) } var reply string //调用rpc服务的指定方法 err = client.Call("HelloService.Hello", "RPC", &reply) if err != nil { log.Fatal(err) } fmt.Println(reply) }
启动server.go 之后启动client.go ,RPC调用成功,控制台分别打印:
// server got req RPC // client hello:RPC
以上就是Golang RPC的原理与简单调用详解的详细内容,更多关于Golang RPC的资料请关注脚本之家其它相关文章!