跨语言的RPC

跨语言的RPC

前言

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

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

案例

首先是基于JSON编码的重新实现

package main

import (
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

type HelloService struct {

}

func (p *HelloService) Hello(requset string,reply *string)error  {
	*reply = "hello:"+requset
	return nil

}

func main() {
	rpc.RegisterName("HelloService",new(HelloService))
	listener,err :=net.Listen("tcp",":1234")
	if err != nil {
		log.Fatal("ListenTCP error",err)
	}
	for  {
		conn,err:=listener.Accept()
		if err != nil {
			log.Fatal("Accept error",err)
		}
		go rpc.ServeCodec(jsonrpc.NewServerCodec(conn))
	}
}

代码和我们之前最大的区别就是用rpc.ServeCodec()代替了rpc.ServeConn()函数,传入的参数是针对服务器端的JSON编解码器。

然后时实现JSON版本的客户端:

package main

import (
	"fmt"
	"log"
	"net"
	"net/rpc"
	"net/rpc/jsonrpc"
)

func main() {
	conn,err:=net.Dial("tcp","localhost:1234")
	if err != nil {
		log.Fatal("net Dial",err)
	}
	client:=rpc.NewClientWithCodec(jsonrpc.NewClientCodec(conn))
	var reply string
	client.Call("HelloService.Hello","hello",&reply)
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply)
}

先使用net.Dial()函数建立TCP链接,然后基于该链接建立针对客户端的JSON编解码器。

在确保客户端可以正常调用RPC服务的方法之后,我们用一个普通的TCP服务代替Go 语言的RPC服务,我门先关闭前面我们编写的服务器端的代码,然后在命令行中输入 nc -l 1234启动一个相同端口号的tcp服务,然后再执行一次客户端的代码,这时我们就可以在nc中看到以下信息

{"method":"HelloService.Hello","params":["hello"],"id":0}

这是一个JSON编写的数据,其中method部分对应要调用的RPC服务和方法组合成的名字,params部分的第一个元素为参数,id是由调用放维护的唯一的调用编号

请求的JSON数据对象在内部其实对应了两个结构体,他们的结果基本相同,客户端是clientRequest,服务器端是serverRequest。

type	clientRequest struct{
  Method string			'json:"method"'
  Params [1]interface{} 'json:"params"'
  Id			uint64				'json:id'
}

type	serverRequest struct{
  Method string			'json:"method"'
  Params [1]interface{} 'json:"params"'
  Id			uint64				'json:id'
}

在获取到RPC调用对应的JSON数据后,可以通过直接向架设了RPC服务的TCP服务器发送JSON数据模拟RPC方法调用

echo -e '{"method":"HelloService.Hello","params":["hello"],"id":1}'|nc lacalhost 1234

返回如下

{"id":1,"result":"hello:hello","error":null}

其中id对应输入的id参数,result为返回的结果,error部分在出问题时表示错误信息。对顺序调用来说,id不是必须的。但是GO语言的RPC框架支持一步调用,当返回结果的顺序和调用的顺序不一样时,可以通过id来识别对应的调用。

总结

经过上面的学习,我们知道,无论采用任何的语言,只要遵循了相同的JSON的结构,以同样的流畅就可以和GO语言编写RPC服务进行通信,这样就实现了跨语言的RPC。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
语言 RPC 框架 Thrift 是一个开源的高效通信协议和序列化框架,可以用于构建语言的客户端和服务器端应用程序。 下面是一个简单的 Thrift 实战示例: 1. 定义 Thrift 文件:首先,我们需要创建一个 .thrift 文件来定义我们的 RPC 接口和数据结构。例如,我们可以创建一个名为 "calculator.thrift" 的文件,其中包含以下内容: ``` namespace java com.example.calculator namespace py calculator service CalculatorService { i32 add(1: i32 num1, 2: i32 num2), i32 subtract(1: i32 num1, 2: i32 num2), i32 multiply(1: i32 num1, 2: i32 num2), double divide(1: double num1, 2: double num2) } ``` 2. 生成代码:使用 Thrift 编译器将 .thrift 文件生成相应语言的代码。例如,我们可以使用以下命令生成 Java 和 Python 的代码: ``` thrift --gen java calculator.thrift thrift --gen py calculator.thrift ``` 这将生成相应语言的客户端和服务器端代码。 3. 实现服务器端:在服务器端,我们需要实现 Thrift 定义的接口。对于 Java,我们可以编写一个实现 CalculatorService 接口的类,并在该类中实现具体的业务逻辑。对于 Python,我们可以编写一个类似的实现。 4. 启动服务器:在服务器上启动 Thrift 服务器,以便接受客户端的请求。不同语言的服务器实现方式可能有所不同,但通常都需要提供一个监听指定端口的入口。 5. 实现客户端:在客户端,我们可以使用生成的客户端代码来调用服务器端的接口。对于 Java,我们可以创建一个 Thrift 客户端,并使用生成的代码来调用服务器端提供的方法。对于 Python,我们可以编写相应的客户端代码。 6. 运行客户端:运行客户端代码,通过网络连接到服务器,并发送请求调用服务器端的方法。 以上是一个简单的 Thrift 实战示例。请注意,具体的实现方式和步骤可能因语言和框架而异,但基本原理是相似的。Thrift 还支持更多高级特性,如异步调用、连接池等,可以根据具体需求进行扩展和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值