在DBus中是否有任何具有信号功能的RPC框架?
我们目前正在寻找RPC
框架,但不幸的是我们无法找到任何具有信号功能但我们需要它。我们查看了gRPC
,Apache Thrift
,Cap-n-Proto
,发现其中没有一个人提供了像DBus那样的开箱即用功能。值得一提的是,我们需要它作为IPC。另外,我们需要监视另外一个套接字,一个用于RPC服务器,另一个用于另一个服务器。在DBus
我们可以将它添加到glib的主循环中。我们的目标RPC必须允许这个。在DBus中是否有任何具有信号功能的RPC框架?
P.S. DBus
并不是我们所需要的,因为我们只需要客户端 - 服务器体系结构而不是client-bus-daemon。
P.P.S.关于off-topic
- 我在这个问题上什么都没有看到需要自以为是的答案。答案应该包含事实而不是意见。
信号可以通过几种不同的方式在Cap'n Proto之上实现。对象
的
链有一个头儿原RPC调用花很长的时间才能完成没有问题。同一连接上的其他呼叫可以正常继续,并且一次可以有多个未决呼叫。因此,接收信号的一种策略是在返回之前等待信号。
许多RPC系统支持挂电话,但有一个额外的挑战:如果你有一个信号流,以及客户端观察流中的每个信号,然后事情就变得复杂,如果正在产生新的信号,这一点很重要客户端比RPC更快地读取它们。您需要为每个客户端保留一个缓冲区。但如果客户死亡并停止提出请求会怎么样?现在,您需要某种超时后清除它。
与大多数其他RPC系统不同,Cap'n Proto支持即时生成新对象。因此,您可以将您的信号流表示为一系列对象。例如:
struct MyPayload { ... }
interface MyInterface {
subscribe @0() -> (firstSignal :Signal(MyPayload));
# Subscribe to signals from this interface.
}
interface Signal(Type) {
# One signal in a stream of signals. Has a payload, and lets you
# wait for the next signal.
get @0() -> (value :Type);
# Gets the payload value of this signal. (Returns immediately.)
waitForNext @1() -> (nextSignal :Signal(Type));
# Waits for the next signal in the sequence, returning a new
# `Signal` object representing it.
}
这极大地简化了,因为头儿原服务器端状态管理,尽快将自动调用每个对象的析构函数,因为所有的客户都表示,他们用它做(通过破坏客户端参考,又名“放弃”它)。如果客户端断开连接,则其所有引用都将被隐式删除。
回调
因为头儿原允许在两个方向上的RPC调用(客户端 - >服务器和服务器 - >客户端),你可以实现一个“信号”或者发布/使用回调订阅机制:
struct MyPayload { ... }
interface MyInterface {
subscribe @0 (cb :Callback(MyPayload)) -> (handle :Handle);
}
interface Callback(Type) {
call @0 (value :Type);
}
interface Handle {}
客户端调用subscribe()
并传递回调对象cb
。然后,服务器可以随时在发出信号时回拨给客户端。
请注意subscribe()
返回一个Handle
,这是一个没有方法的对象。这样做的目的是检测客户何时退订。如果客户端丢弃handle
,则会通知服务器(服务器端对象的析构函数将运行),然后服务器可以注销回调。这也处理客户端断开连接的情况 - 所有对象引用都隐式地断开连接。
乍一看,由于其简单性,该解决方案可能看起来比链式对象解决方案好得多。但是,它有一个问题,即现在您的对象引用指向两个方向,这可能导致循环。在客户端代码中,必须小心确保回调实现不“拥有”保持注册的句柄,否则它永远不会被清理(连接关闭时除外)。在等待服务器取消注册回调的同时,您还必须确保在删除句柄后短时间内仍可以调用回调。这些问题并没有出现在对象链解决方案中,这可能会使解决方案的实施更加清晰。
其他RPC系统
我讨论上面,因为我是作家,是因为它提供了比大多数RPC系统更多的选择头儿原。
如果你使用gRPC,你可以使用它的“流媒体”功能来支持类似信号的东西。流式RPC可以随着时间的推移返回多个响应。
我不确定节俭。我最后一次尝试它时,请求必须是FIFO,这意味着长时间运行的RPC是不可能的。然而,那是很久以前的事了,也许从那以后它就变了。
你能否告诉我如果我不想在第一次接收到信号后取消注册回调?你的意思是我应该在某处存储'Handle'吗? –
@VictorPolevoy客户应该把'Handle'保存在内存中,是的。虽然可能不会存储到磁盘,因为整个操作都与特定的实时网络连接有关。如果连接死亡,那么回调将不再起作用。客户端需要重新连接并注册新的回调。 –
有没有一种方法可以通过提供capnp数据缓冲区来解析从套接字接收的来自外部的套接字? –