eRPC 的默认的设计模型是简单的主从模式,也就是设备A上运行服务,另一个设备B主动发起请求调用A的服务,但在实际的应用中,我们需要双向的请求,也就是说设备A,设备B互为主从,两台设备上都会运行服务供对方调用。在这种模式下,原有的串行通讯传输(SerialTransport)实现就不能满足要求,因为设备接收到的数据无法知道是给server的请求(Requst),还是给client的响应(Response)。
如果要实现上述的双向请求并不复杂,只要修改串行通讯传输(SerialTransport)的实现,在发送数据时,多发送一个数据类型的标志,这样接收方收到数据时先判断这个标志,如果是给server端的Request,后续的数据就让server接收,如果是给client端的Response,就让client接收。
由此就可以实现一个支持双向请求的串行数据传输(dual serial transport).通过只修改传输层,就可以让eRPC框架实现client/server混合运行。
如下图是Dual serial transport的实现模型。
因为client/server混合运行时,client和server都会发送数据也都会接收数据,所以关键的问题就是通过数据类型标志(segType),让接收到的数据被正确的接收端(client或server)接收。
为了防止client/server的数据发送能同时正常执行,设计了一个发送数据互斥锁(send_lock),使用互斥锁将client和server发送数据的操作严格区分开。
在发送正式数据之前先发送一个数据类型标志(segType)标志
为了确保client/server能正确收到自己应该接收的数据,设计了三个数据接收信号量:
变量名 | 说明 | 备注 |
---|---|---|
server_semaphore | server 端数据接收信号量 | 初始状态下server端接收请求数据时被此信号量阻塞,等待被开关线程收唤醒 |
client_semaphore | client 端数据接收信号量 | 初始状态下cliennt端接收响应数据时被此信号量阻塞,等待被开关线程收唤醒 |
switch_semaphore | 数据开关线程 数据接收信号量 | 开关线程负责读取数据类型标志(segType),并根据标志唤醒server或client接收数据 |
当数据开关线程唤醒server或client接收数据后,自己就进入阻塞状态,等待server或client端的唤醒 当server或client被被开关线程收唤醒接收完数据后,会设置switch_semaphore信号量唤醒开关线程准备接收下一个数据类型标志(segType)
上述三个数据接收信号量和发送数据互斥锁定义在
数据开关线程的实现在:
DualSerialTransport::serverThread
在原有的SerialTransport的数据发送函数基础上,DualSerialTransport 做了简单修改,增加了信号量等待和发送数据类型标志(segType)动作,参见:
DualSerialTransport::underlyingSend
在原有的SerialTransport的数据接收函数基础上,DualSerialTransport 增加了信号量等待动作,参见:
DualSerialTransport::underlyingReceive
关于双向数据传输完整的测试代码参见