一、据一位资深的网友说QLocalSocket有问题,共享内存QSharedMemory也有,比如存在多线程问题,不灵活,丢数据等问题都有,而且还占资源。血的教训。后来换成了zmq+protobuf。ZMQ进程内,进程间,机器间(跨电脑)都可以实现通信。
二、推荐使用ZMQ
1、ZeroMQ简称ZMQ
ZMQ(zeromq)被称为史上最快的“消息队列”,它处于会话层之上,应用层之下,使用后台异步线程完成消息的接受和发送,近乎完美的封装了Socket API,大大简化了编程人员的复杂度。其作为消息中间件,在IPC通信领域应用广泛。
ZeroMQ号称是“史上最快的消息队列”,基于c语言开发的,实时流处理sorm的task之间的通信就是用的zeroMQ。引用官方说法,ZMQ是一个简单好用的传输层,像框架一样的一个socket library,他使得Socket编程更加简单、简洁和性能更高。是一个消息处理队列库,可在多个线程、内核和主机盒之间弹性伸缩。但是,它无疑是极具前景的、并且是人们更加需要的“传统”BSD套接字之上的一层封装。ZMQ让编写高性能网络应用程序极为简单和有趣。确实,它跟RabbitMQ,ActiveMQ之类有着相当本质的区别,ZeroMQ根本就不是一个消息队列服务器,更像是一组底层网络通讯库。
2、ZMQ 4种模型
一对一结对模型(Exclusive-Pair),可以认为是一个TCP Connection,但是TCP Server只能接受一个连接。数据可以双向流动,这点不同于后面的请求回应模型。
请求回应模型(Request-Reply),由Client发起请求,并由Server响应,跟一对一结对模型的区别在于可以有多个Client。
发布订阅模型(Publish-Subscribe),Publish端单向分发数据,且不关心是否把全部信息发送给Subscribe端。如果Publish端开始发布信息时,Subscribe端尚未连接进来,则这些信息会被直接丢弃。Subscribe端只能接收,不能反馈,且在Subscribe端消费速度慢于Publish端的情况下,会在Subscribe端堆积数据。
管道模型(Push-Pull),从 PUSH 端单向的向 PULL 端单向的推送数据流。如果有多个PULL端同时连接到PUSH端,则PUSH端会在内部做一个负载均衡,采用平均分配的算法,将所有消息均衡发布到PULL端上。与发布订阅模型相比,管道模型在没有消费者的情况下,发布的消息不会被消耗掉;在消费者能力不够的情况下,能够提供多消费者并行消费解决方案。该模型主要用于多任务并行。
这4种模型总结出了通用的网络通信模型,在实际中可以根据应用需要,组合其中的2种或多种模型来形成自己的解决方案。
ZMQ可以基于多种传输协议进行通信,包括TCP、UDP、in-process(进程内通信)等。ZMQ提供进程内(inproc://)、进程间(ipc://)、机器间(tcp://)、广播(pgm://)等四种通信协议。
创建一个消息流
int zmq_bind (void *socket, const char *endpoint);
int zmq_connect (void *socket, const char *endpoint);
bind函数是将socket绑定到本地的端点(endpoint),而connect函数连接到指定的peer端点。
endpoint支持的类型:
void* context = zmq_ctx_new();
void* responder = zmq_socket(context, ZMQ_REP);
int rc = zmq_bind(responder, "inproc://hello");
assert(rc == 0);
void* client = zmq_socket(context, ZMQ_REQ);
zmq_connect(client, "inproc://hello");
int rc = zmq_bind(socket, "ipc:///tmp/feeds/0");
assert (rc == 0);
int rc = zmq_connect(socket, "ipc:///tmp/feeds/0");
assert (rc == 0);
void *context = zmq_ctx_new ();
void *responder = zmq_socket (context, ZMQ_REP);
int rc = zmq_bind (responder, "tcp://*:5555");
assert (rc == 0);
void *context = zmq_ctx_new ();
void *requester = zmq_socket (context, ZMQ_REQ);
zmq_connect (requester, "tcp://localhost:5555");
3、ZMQ处理进程内通信的原理
其实就是线程之间通过两个队列来交互,对于每个线程来说都是通过其中一个队列发消息给对方,从另一个队列中读取对方发送的消息。zmq所做的就是把pipe绑定到对应的线程上,然后在send和recv的时候通过pipe来发出、获取信息。
4、ZMQ的服务器端和客户端的启动没有固定的先后顺序。
ZMQ的设计允许服务器端和客户端在启动时没有固定的先后顺序。这意味着,无论是服务器端还是客户端,都可以首先启动。这种设计提供了更大的灵活性,使得系统的部署和扩展更加方便。
具体来说:
服务器端可以首先启动,通过调用zmq_bind函数绑定到指定的地址,并开始监听连接。一旦服务器端启动并准备好,它就可以等待客户端的连接请求。
客户端也可以在服务器端之前启动,通过调用zmq_connect函数尝试连接到服务器。如果服务器尚未启动,客户端的连接请求会在后台异步重试,直到成功连接到服务器。
5、ZMQ编译
ZMQ 是一个高性能, 易使用, 易配置的 Socket 库, 在 linux 里面一句命令能够安装, 但是其 windows 版本安装, 要使用cmake手动编译。
6、官网
https://zeromq.org/
https://github.com/zeromq/libzmq
c语言封装
https://github.com/zeromq/czmq
c++语言封装
https://github.com/zeromq/cppzmq
---
参考文献
Qt网络编程-ZMQ的使用_qt zmq-CSDN博客
【Qt 学习之路】在 Qt 使用 ZeroMQ_qt zeromq-CSDN博客
https://www.cnblogs.com/chenny7/p/6245236.html
https://zhuanlan.zhihu.com/p/346230632