2017-01-16 141 views
3

我们目前正在寻找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 - 我在这个问题上什么都没有看到需要自以为是的答案。答案应该包含事实而不是意见。

回答

6

信号可以通过几种不同的方式在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是不可能的。然而,那是很久以前的事了,也许从那以后它就变了。

+0

你能否告诉我如果我不想在第一次接收到信号后取消注册回调?你的意思是我应该在某处存储'Handle'吗? –

+0

@VictorPolevoy客户应该把'Handle'保存在内存中,是的。虽然可能不会存储到磁盘,因为整个操作都与特定的实时网络连接有关。如果连接死亡,那么回调将不再起作用。客户端需要重新连接并注册新的回调。 –

+0

有没有一种方法可以通过提供capnp数据缓冲区来解析从套接字接收的来自外部的套接字? –

相关问题