如何在Linux下反转POSIX消息队列方向实现单队列半双工双向通信
单个POSIX消息队列实现半双工双向通信方案
需求背景
需仅使用单个POSIX消息队列完成客户端与服务端进程间的双向通信,本质为半双工配置:支持双向传输,但同一时间消息仅能沿一个方向传输,无需支持同时收发。通信永远由客户端发送第一条消息发起,不存在服务端初始主动发消息的冲突场景,不考虑共享内存、System V消息队列、管道、TCP/UDP等其他进程通信方案。
现有双队列实现参考
当前主流方案为创建两个独立队列分别处理两个方向的传输,实现代码如下:
客户端代码
... int read = mq_open("servertoclient", O_RDWR | O_CREAT, 0600, 0); int write = mq_open("clienttoserver", O_RDWR | O_CREAT, 0600, 0); char send_buffer[8192]; mq_send(write, send_buffer, 8192, 0); //向服务端发送消息 char receive_buffer[8192]; mq_receive(read, receive_buffer, 8192, 0); //接收服务端返回的响应 mq_close(write); mq_close(read); mq_unlink("servertoclient"); mq_unlink("clienttoserver"); ...
服务端代码
... int write = mq_open("servertoclient", O_RDWR | O_CREAT, 0600, 0); int read = mq_open("clienttoserver", O_RDWR | O_CREAT, 0600, 0); char send_buffer[8192]; mq_send(write, send_buffer, 8192, 0); //向客户端发送消息 char receive_buffer[8192]; mq_receive(read, receive_buffer, 8192, 0); //接收客户端返回的响应 mq_close(write); mq_close(read); mq_unlink("servertoclient"); mq_unlink("clienttoserver"); ...
单队列半双工实现方案
采用对讲机式的方向控制逻辑,通过特殊编码的控制消息标记传输方向反转,无需频繁切换队列打开权限,调用mq_open时直接指定O_RDWR模式打开队列即可,通过协议层面的收发约定避免读写冲突。
控制消息约定
预先定义两类特殊控制消息,与普通业务数据做区分:
- 方向反转控制消息:内容固定为特殊标识(例如
__TURNAROUND__),发送方完成所有业务数据发送后发送该消息,通知接收方可以切换为发送状态 - 终止控制消息:内容固定为特殊标识(例如
__TERMINATE__),通知对方通信结束,可执行退出流程
客户端实现逻辑
- 调用
mq_open以O_RDWR | O_CREAT权限打开单个公共队列,权限设为0600 - 发送所需业务数据,全部发送完成后发送方向反转控制消息
- 进入接收状态,循环读取队列消息:
- 收到业务数据则直接处理
- 收到方向反转控制消息,结束当前接收流程,切换回发送状态
- 收到终止控制消息,进入退出流程
- 退出流程:关闭队列描述符,调用
mq_unlink销毁队列后退出
服务端实现逻辑
- 调用
mq_open以O_RDWR | O_CREAT权限打开同一个公共队列 - 初始进入接收状态,循环读取队列消息:
- 收到业务数据则直接处理
- 收到方向反转控制消息,结束当前接收流程,切换为发送状态
- 收到终止控制消息,进入退出流程
- 发送状态下发送处理后的返回业务数据,全部发送完成后发送方向反转控制消息,切换回接收状态
- 退出流程:关闭队列描述符,调用
mq_unlink销毁队列后退出
实现注意点
- 双方严格遵循“发送完才接收,接收完等反转消息才发送”的约定,因通信由客户端发起,初始仅客户端处于发送状态,不会出现双方同时写队列的冲突
- 可配合消息优先级做区分:例如业务数据用优先级1,控制消息用优先级2,接收时可优先识别控制消息,避免与业务数据混淆
内容的提问来源于stack exchange,提问作者Java Weenis
相关产品推荐
相关产品推荐

