跨语言客户端/服务器的双向RPC选项
我正在构思一个项目的想法,想要在客户端用Python开发一个图形用户界面(GUI),然后这个界面可以通过远程过程调用(RPC)与后端用其他语言编写的程序进行交互。具体来说,我现在在客户端使用PyQt,而后端则是用Go语言。
我的目标如下:
- PyQt客户端
- 角色: 视图,控制器
- 单向调用(信号/槽),比如:
button.clicked -> RPC.handleSignal
- 请求/回复RPC,比如:
rowCount = model.rowCount -> RPC.call.model.rowCount
- 无关语言的后端(这里是Go)
- 角色: 控制器,模型
- 单向调用(发出信号),比如:
model.dataChanged -> RPC.emitSignal
我称这些为控制器角色,因为用户可以在客户端的GUI中定义信号和槽的连接,或者后端可以通过RPC定义自己的信号和槽连接,前提是它知道客户端的视图。这完全取决于用户想如何设置控制器。
我现在在考虑使用Thrift,或者说使用一种更简单的RPC,没有接口描述语言(IDL)。但我主要想问的是,尝试用两个.thrift文件来做Thrift,分别是客户端/服务器 <----> 客户端/服务器(两个连接),以实现双向功能,这样的做法会不会很乱?我觉得使用Thrift的好处在于它有IDL,这样我可以专门构建我的接口,而后端代码只需实现他们想要的部分。
有没有人对这个问题有推荐的解决方案?使用两个Thrift接口?一个Thrift接口,提供一个服务让客户端建立第二个简单的socket,以接收来自服务器的单向调用?还是说在这里使用Thrift有点过于复杂?虽然后端到GUI的接口实际上只是一个服务功能,但GUI到后端的功能可能会稍微扩展一下(比如模型处理器、槽处理器、一般的服务器状态查询)。
(编辑)更多想法
我在想,这种模式可以用任何RPC框架来实现,流程大概是这样的:
- 后端服务器进程启动;监听某个端口
- 客户端GUI启动;连接到服务器的RPC;监听新的端口;通过RPC调用将端口发送给服务器
- 服务器接收到客户端的端口,并绑定到这个端口以建立第二个RPC连接
- 客户端和服务器有两个连接,以实现双向RPC
1 个回答
在网络上,当你通过TCP(或者其他类似的连接协议)连接到服务器时,你的电脑会选择一个(伪随机的)端口来接收服务器的回复。只要服务器保持连接,并且双方都保持连接活跃,你就已经建立了双向连接。所以从技术的角度来看,你并不需要再发起第二个连接。
根据你的RPC系统,它可能会使用TCP,也可能不会,并且可能会有双向通信(或者说,可能需要初始化双向通信)。
现在,关于thrift,似乎还没有太多文档(没有API参考)。不过查看示例代码后,似乎它把连接处理的细节隐藏起来,只使用请求/响应的通信方式。所以在这种情况下,是的,你需要在客户端监听一个定义好的端口,并告诉服务器,这样服务器才能发起请求/响应的通信。
Go本身提供了rpc包,这个包是专门为Go数据设计的,所以对你没有帮助。
不过,它还提供了websocket包。虽然最初是为了网页服务器和浏览器之间的通信,但它是一个双向协议(这就是它的核心),可以被任何类型的应用使用。虽然在大小和带宽方面可能不够高效,但它能完成任务。
我不太确定Go包的实现状态。Conn类型确实有一个origin字段,但Conn.Dial函数示例中传入的是http://localhost
; 我不确定这是否会被替换为一个可以远程访问的websocket源。Handler.ServeHTTP函数提供了一个http.ResponseWriter,你可能也可以用它来发起连接。至少这是我会首先测试的内容。
如果你对使用定义好的数据格式和自己处理网络连接感到舒服,可以考虑protobuf。这里有一个社区项目为Go绑定protobuf。这样你就可以自己处理TCP连接(连接到它,发送数据,接收数据,保持连接信息等)。
至于其他替代方案,你可以查看社区包页面或者社区项目页面(特别是Go Ajax和go-xmlrpc——不过这两个目前都非常基础)。