跨语言客户端/服务器的双向 RPC 选项

发布于 2024-12-10 11:08:28 字数 1309 浏览 0 评论 0原文

我正在尝试为一个项目提出一个想法,其中客户端 GUI 可以用 python 开发,并且 GUI 可以由后端以任何其他语言通过 RPC 驱动。 更具体地说,现在我在客户端使用 PyQt,并使用 Go 作为初始后端。

这是我的目标:

  • PyQt 客户端
    • 角色:视图、控制器
    • 单向调用(SIGNAL/SLOT),例如:button.clicked -> RPC.handleSignal
    • 请求/回复RPC,如:rowCount = model.rowCount -> RPC.call.model.rowCount
  • 不可知后端(在本例中为 Go)
    • 角色:控制者、模型
    • 单向调用(发出信号),例如:model.dataChanged -> RPC.emitSignal

我将其中每一个都称为具有控制器角色,因为用户可以在 GUI 客户端中定义信号/槽连接,或者后端可以通过 RPC 定义自己的信号/槽连接,假设了解在客户端查看。这仅取决于用户想要如何设置控制器。

我现在正在考虑 Thrift,而不是没有 IDL 的轻量级基本 RPC。但我主要的问题是,尝试将 Thrift 作为两个 .thrift 文件、客户端/服务器 <----> 来执行是否会是一种混乱的方法。客户端/服务器(两个连接),以获得双向功能?我看到 Thrift 的好处是 IDL,这样我就可以专门构建我的界面,而后端代码可以只实现他们想要的部分。

有人建议解决这个问题吗?两个 Thrift 接口?一个 Thrift 接口,提供一项服务让客户端建立第二个简单套接字以接收来自服务器的单向调用?或者说 Thrift 在这里有点矫枉过正了?而后端-> GUI界面实际上只是一个单一的服务功能,GUI ->后端可以扩展一点(modelHandlers、slotHandlers、一般服务器状态查询)。

(编辑)更多想法

我的一部分想法是,该模式可以使用任何 RPC 框架来完成,而且会是这样的吗?

  1. 后端服务器进程启动;监听端口
  2. 客户端 GUI 启动;连接到服务器 RPC;监听新端口;通过 RPC 调用将端口发送到服务器
  3. 服务器从客户端接收端口,并绑定到该端口以进行第二个 RPC 连接
  4. 客户端和服务器有 2 个连接,用于双向 RPC

I'm trying to lay out an idea for a project, where a client-side GUI can be developed in python, and the GUI can be driven by a backend in potentially any other language, over RPC.
More specifically, right now I am working with PyQt on the client side, and Go as the initial backend.

Here are my goals:

  • PyQt client
    • Roles: View, Controller
    • Oneway calls (SIGNAL/SLOT), such as: button.clicked -> RPC.handleSignal
    • Request/Reply RPC, such as: rowCount = model.rowCount -> RPC.call.model.rowCount
  • Agnostic backend (Go in this case)
    • Roles: Controller, Model
    • Oneway calls (Emit SIGNAL), such as: model.dataChanged -> RPC.emitSignal

I refer to each of these as having controller roles becase a user could define signal/slot connections in the GUI client side, or the backend could define its own signal/slot connections over RPC, assuming knowledge about the view on the client side. It would depend solely on how the user wants to set up the controller.

I am looking at Thrift right now, vs say a lighter weight basic rpc without an IDL. But mainly my question is whether it would be a messy approach to try and do Thrift as two .thrift files, with client/server <----> client/server (two connections), in order to get the bi-directional functionality? The benefit I see with Thrift is the IDL, so that I can build my interface specifically, and backend code can just implement the parts they want.

Does anyone have a recommendation for a solution to this? Two Thrift interfaces? One Thrift interface, that provides a service to let the client establish a second simple socket to receive oneway calls from the server? Or is Thrift somewhat even overkill here? While the backend -> GUI interface is really only a single service function, the GUI -> backend could expand a bit (modelHandlers, slotHandlers, general server status queries).

(Edit) More Thoughts

Part of me is thinking that the pattern could be done with any RPC framework, and it would be like this?

  1. Backend server process starts; listens on port
  2. Client GUI starts; connects to server RPC; listens on new port; sends port to server via RPC call
  3. Server receives port from client, and binds to it for a second RPC connection
  4. Client and Server have 2 connections, for bi-directional RPC

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

殊姿 2024-12-17 11:08:28

在网络上,当您通过 TCP(或任何其他类似的基于连接的协议)连接到服务器时,连接时您的 PC 已经选择并侦听(伪/相对)随机端口,以便接收服务器答案。因此,只要服务器保持连接并且双方保持连接活动,您就已经拥有了双向连接。因此,从技术、低级别的角度来看,您不需要启动第二个连接

根据您的 RPC 系统,它可能会或可能不会使用 TCP,并且它可能会也可能不会具有双向通信(或者更确切地说,双向通信初始化)。

现在,对于 thrift,似乎还没有太多文档(没有 API 参考)。但检查示例代码似乎抽象了连接处理并仅使用请求/响应通信。因此,在这种情况下,是的,您必须在客户端定义的端口上侦听并告诉服务器,以便服务器可以发起请求/响应通信

Go本身提供了rpc包,这是go data独有的,所以不会帮助你。

不过,它还提供了 websocket。虽然最初的目标是网络服务器到网络浏览器的通信,但它是一种双向协议(这毕竟是它的含义),并且可以由任何应用程序类型使用。它可能在大小/带宽方面效率不高,但它可以完成工作。

我不确定 go 包中的实现状态。 Conn 类型确实有一个 origin 字段,但 Conn.Dial 函数示例传递 http://localhost;我不确定这是否会被替换为可远程访问的 websocket 源。 Handler.ServeHTTP 函数提供了一个 http.ResponseWriter,您可以使用它来启动连接也是如此。 至少这是我要测试的第一件事。

如果您习惯使用定义的数据格式并自己处理网络,则另一种选择是protobuf。有一个用于 go 绑定到 protobuf 的社区项目。然后,您可以自己处理 TCP 连接(连接到它并发送数据、接收数据、保存连接信息等)。

至于其他替代方案,您可能需要查看社区包页面和/或社区项目页面(尤其是 Go Ajax 和 go-xmlrpc – 目前两者都非常初级) 尽管)。

On the network when you connect to a server via TCP (or any other similar connection based protocol), when connecting your PC already chooses and listens on a (pseudo/relatively) random port in order to receive the servers answers. So for that matter, as long as the server keeps the connection and both sides keep the connection alive you already have a bi-directional connection. So from a technical, low-level point of view you do not need to initiate a second connection.

Depending on your RPC system it may or may not use TCP and it may or may not feature bi-directional communication (or rather, bi-directional communication initialization).

Now, for thrift, there does not seem to be much documentation there yet (no API reference). But checking the example code it seems to abstract the connection-handling away and use request/response communication only. So in this case, yes, you would have to listen on a defined port client side and tell the server, so the server can initiate a request/response communication.

Go itself provides the rpc package, which is exclusive to go data, so will not help you.

However, it also provides the websocket package. Although initially targeted at webserver to webbrowser communications it is a bi-directional protocol (that’s what it’s about after all) and can be used by any application type. It may not be as efficient size-/bandwidth-wise but it does the job.

I’m not sure about the state of implementation in the go package. The Conn type does have an origin field but the Conn.Dial function example passes http://localhost; I’m not sure whether this is replaced with a remotely-accessible websocket origin. The Handler.ServeHTTP function provides an http.ResponseWriter, which you can probably use to initiate connection as well. At least that’s the first thing I would test.

An alternative, if you are comfortable with using a defined dataformat and handle networking yourself, is protobuf. There is a community project for go bindings to protobuf. You could then handle the TCP connection yourself (connecting to it and sending your data, receiving the data, holding the connection info etc).

As for other alternatives, you may want to check the community packages page and or the community projects page (especially the Go Ajax and go-xmlrpc – both are very rudimentary at this point though).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文