python有rpc开发的相关协议,同样go也有rpc的序列化协议Gob。
标准库的RPC默认采用Go语言特有的gob编码,因此从其它语言调用Go语言实现的RPC服务将比较困难。在互联网的微服务时代,每个RPC以及服务的使用者都可能采用不同的编程语言,因此跨语言是互联网时代RPC的一个首要条件。得益于RPC的框架设计,Go语言的RPC其实也是很容易实现跨语言支持的。
go语言的json序列化RPCGo语言的RPC框架有两个比较有特色的设计:一个是RPC数据打包时可以通过插件实现自定义的编码和解码;另 一个是RPC建立在抽象的io.ReadWriteCloser接口之上的,我们可以将RPC架设在不同的通讯协议之上。这里我们将尝试通过官方自带的net/rpc/jsonrpc扩展实现一个跨语言的RPC。
首先是基于json编码重新实现RPC服务:
python使用json协议rpc和go通信服务端程序示例:
package main import ( "net" "net/rpc" "net/rpc/jsonrpc" ) type HelloService struct {} func (s *HelloService) Hello(request string, reply *string) error { *reply = "hello "+ request return nil } func main(){ //注册处理逻辑 rpc.RegisterName("HelloService", new(HelloService)) // 实例化一个server listener, err := net.Listen("tcp", ":1234") if err != nil { panic("启动错误") } for { // 使用for可以防止客户端访问一次之后服务端退出 // 启动服务 conn, err := listener.Accept() if err != nil { panic("接收") } // 开启携程 go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) } }
客户端程序示例:
package main import ( "fmt" "net" "net/rpc" "net/rpc/jsonrpc" ) func main(){ conn, err := net.Dial("tcp", "localhost:1234") if err != nil { panic("连接错误") } client := rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn)) var reply string err = client.Call("HelloService.Hello", "vistor", &reply) if err != nil { panic("调用错误") } fmt.Println(reply) }
运行结果:
我们使用go做服务端,python做客户端,利用json的rpc进行通信。
替换TCP传输协议为Httpgo服务端程序示例:
package main import ( "net" "net/rpc" "net/rpc/jsonrpc" ) type HelloService struct {} func (s *HelloService) Hello(request string, reply *string) error { *reply = "hello "+ request return nil } func main(){ //注册处理逻辑 rpc.RegisterName("HelloService", new(HelloService)) // 实例化一个server listener, err := net.Listen("tcp", ":1234") if err != nil { panic("启动错误") } for { // 使用for可以防止客户端访问一次之后服务端退出 // 启动服务 conn, err := listener.Accept() if err != nil { panic("接收") } // 开启携程 go rpc.ServeCodec(jsonrpc.NewServerCodec(conn)) } }
python客户端程序示例:
# _*_ coding:utf-8 _*_ __author__ = 'wulian' __date__ = '2022/4/19 0019 9:51' import json import socket # 因为服务端是TCP协议,所以我们直接使用socket request = { "id":0, "params":["pythoner"], "method":"HelloService.Hello" } client = socket.create_connection(("localhost", 1234)) client.sendall(json.dumps(request).encode()) # 获取服务器返回的数据 rsp = client.recv(1024) # 接收到的数据是二进制文本 rsp = json.loads(rsp.decode()) print(rsp)
运行结果:
上面的程序实现了go自身的的rpc通信以及go和python的rpc通信,但是通信协议为TCP,显然不利于WEB开发。那么如何实现go和python的http协议rpc通信呢?
go的 rpc通信问题总结服务端程序示例:
package main import ( "io" "net/rpc" "net/http" "net/rpc/jsonrpc" ) type HelloService struct {} func (s *HelloService) Hello(request string, reply *string) error { *reply = "hello "+ request return nil } func main() { // 实例化一个server rpc.RegisterName("HelloService", new(HelloService)) http.HandleFunc("/jsonrpc", func(w http.ResponseWriter, r *http.Request) { var conn io.ReadWriteCloser = struct { io.Writer io.ReadCloser }{ ReadCloser: r.Body, Writer: w, } rpc.ServeRequest(jsonrpc.NewServerCodec(conn)) }) // 启动监听 http.ListenAndServe(":1234", nil) }
客户端程序示例:
# _*_ coding:utf-8 _*_ __author__ = 'wulian' __date__ = '2022/4/19 0019 9:51' import requests request = { "id":0, "params":["pythoner"], "method":"HelloService.Hello" } # 因为服务端是http协议,所以我们直接使用python的requests包完成http通信 res = requests.post("http://localhost:1234/jsonrpc", json=request) print(res.text)
运行结果:
上面的示例中存在一个严重问题:业务逻辑和通信连接混在一起,高度耦合。
有没有方法能够解决呢?有,就是 protobuf + grpc
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)