多语言通信基础 03 go和python的rpc通信

多语言通信基础 03 go和python的rpc通信,第1张

python有rpc开发的相关协议,同样go也有rpc的序列化协议Gob。

标准库的RPC默认采用Go语言特有的gob编码,因此从其它语言调用Go语言实现的RPC服务将比较困难。在互联网的微服务时代,每个RPC以及服务的使用者都可能采用不同的编程语言,因此跨语言是互联网时代RPC的一个首要条件。得益于RPC的框架设计,Go语言的RPC其实也是很容易实现跨语言支持的。

go语言的json序列化RPC

Go语言的RPC框架有两个比较有特色的设计:一个是RPC数据打包时可以通过插件实现自定义的编码和解码;另 一个是RPC建立在抽象的io.ReadWriteCloser接口之上的,我们可以将RPC架设在不同的通讯协议之上。这里我们将尝试通过官方自带的net/rpc/jsonrpc扩展实现一个跨语言的RPC。

首先是基于json编码重新实现RPC服务:

服务端程序示例:

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)
}

运行结果:

python使用json协议rpc和go通信

 我们使用go做服务端,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))
	}
}

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)

运行结果:

替换TCP传输协议为Http

上面的程序实现了go自身的的rpc通信以及go和python的rpc通信,但是通信协议为TCP,显然不利于WEB开发。那么如何实现go和python的http协议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)

运行结果:

go的 rpc通信问题总结

上面的示例中存在一个严重问题:业务逻辑和通信连接混在一起,高度耦合。

有没有方法能够解决呢?有,就是 protobuf + grpc

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/718946.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存