zmq recv 退出线程

本文介绍如何设置ZMQ Socket的recv操作超时时间,避免线程暴力退出,探讨使用C语言接口而非C++接口的原因。通过设置ZMQ_RCVTIMEO参数,可以实现recv操作的超时,确保线程能够优雅地退出。

1、设置socket的recv接收操作超时时间,socket.setsockopt(ZMQ_RCVTIMEO,300);
如果设置recv 为阻塞,则不好优雅地退出线程,只能暴力退出。
2、用c语言接口,而不是c++接口。
zmq官网翻译版: https://www.cnblogs.com/fengbohello/p/4398953.html

#include "ZmqSocket.h" #include "zmq.h" #include <QDebug> #include "tracehandle.h" #include "appconfig.h" ZmqSocket * ZmqSocket::m_instance = nullptr; CommandHandle * CommandHandle::m_instance = nullptr; void CommandHandle::createCommand() { ZmqSocket::createCommand(); if (nullptr == CommandHandle::m_instance) { CommandHandle::m_instance = new CommandHandle(); connect(ZmqSocket::getInstance(), SIGNAL(msgRep(QByteArray)), CommandHandle::m_instance, SIGNAL(msgRep(QByteArray)), Qt::UniqueConnection); } } void CommandHandle::testSlot(QByteArray msg) { qDebug() << "CommandHandle testSlot" << msg; //emit msgRep(msg); } void CommandHandle::destroyCommand() { static int index = 0; while (index < 1000) { ++index; if (CommandHandle::m_instance->readMsg().isEmpty()) { break; } QThread::msleep(1); } ZmqSocket::destroyCommand(); if (nullptr != CommandHandle::m_instance) { delete CommandHandle::m_instance; CommandHandle::m_instance = nullptr; } } void CommandHandle::sendMsg(QByteArray msg) { if (nullptr != CommandHandle::m_instance) { CommandHandle::m_instance->appendMsg(msg); } } QByteArray CommandHandle::getMsg() { QByteArray msg; if (nullptr != CommandHandle::m_instance) { msg = CommandHandle::m_instance->readMsg(); } return msg; } CommandHandle::~CommandHandle() { } CommandHandle::CommandHandle(QObject * parent) : QObject(parent) { QThread *thread = new QThread; this->moveToThread(thread); thread->start(); } void CommandHandle::start() { } void CommandHandle::appendMsg(QByteArray msg) { mutex.lock(); if (!m_msgList.contains(msg)) { m_msgList << msg; } mutex.unlock(); } QByteArray CommandHandle::readMsg() { QByteArray msg; mutex.lock(); if (m_msgList.count() > 0) { msg = m_msgList.takeFirst(); } mutex.unlock(); return msg; } void ZmqSocket::createCommand() { if (nullptr == ZmqSocket::m_instance) { ZmqSocket::m_instance = new ZmqSocket(); ZmqSocket::m_instance->start(); } } void ZmqSocket::destroyCommand() { if (nullptr != ZmqSocket::m_instance) { ZmqSocket::m_instance->stopThread(); delete ZmqSocket::m_instance; ZmqSocket::m_instance = nullptr; } } ZmqSocket::~ZmqSocket() { if (nullptr != m_socket) { zmq_close(m_socket); m_socket = nullptr; } if (nullptr != m_ctx) { zmq_ctx_term(m_ctx); m_ctx = nullptr; } } bool ZmqSocket::connect() { bool result = true; // Set the receive timeout for ZMQ to 5 seconds int iRcvTimeout = 500; int iSedTimeout = 10; if (m_socket == nullptr) { m_ctx = zmq_ctx_new(); if (nullptr == m_ctx) { result = false; TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_ctx_new failed.")); } if (result) { m_socket = zmq_socket(m_ctx, ZMQ_REQ); if (nullptr == m_socket) { zmq_ctx_destroy(m_ctx); m_ctx = nullptr; result = false; TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_socket failed.")); } } // if (result) // { // if (zmq_setsockopt(m_socket, ZMQ_SNDTIMEO, &iSedTimeout, sizeof(iSedTimeout)) < 0) // { // zmq_close(m_socket); // zmq_ctx_destroy(m_ctx); // m_socket = nullptr; // m_ctx = nullptr; // result = false; // TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_setsockopt failed.")); // } // } // if (result) // { // if (zmq_setsockopt(m_socket, ZMQ_RCVTIMEO, &iRcvTimeout, sizeof(iRcvTimeout)) < 0) // { // zmq_close(m_socket); // zmq_ctx_destroy(m_ctx); // m_socket = nullptr; // m_ctx = nullptr; // result = false; // TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_setsockopt failed.")); // } // } if (result) { //if (zmq_connect(m_socket, "tcp://10.42.0.1:6666") < 0) //if (zmq_connect(m_socket, "tcp://192.168.68.5:6666") < 0) if (zmq_connect(m_socket, m_ip) < 0) { zmq_close(m_socket); zmq_ctx_destroy(m_ctx); m_socket = nullptr; m_ctx = nullptr; result = false; TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_connect %1 failed.").arg(m_ip)); } } } return result; } void ZmqSocket::stopThread() { m_stop = true; if (isRunning()) { terminate(); } mutex.tryLock(1000); mutex.unlock(); } ZmqSocket::ZmqSocket(QObject * parent) : QThread(parent) { m_stop = false; m_socket = nullptr; m_ctx = nullptr; memset(m_ip, 0x00, 32); strncpy(m_ip, appConfig_getSendAddr().data(), 32 - 1); qDebug()<<"cmd m_ip"<<QString(m_ip); } void ZmqSocket::writeMsgToSocket() { mutex.lock(); QByteArray msg = CommandHandle::getMsg(); if (!msg.isEmpty()) { if (connect()) { TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("Write: %1").arg(QString(msg))); if (zmq_send(m_socket,msg.data(), msg.size(), 0) > 0) { readMsgFromSocket(); } else { TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("zmq_send failed.")); } } else { TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("connect failed.")); } //if (connect() && (zmq_send(m_socket,msg.data(), msg.size(), 0) > 0)) //{ // readMsgFromSocket(); //} } mutex.unlock(); } void ZmqSocket::readMsgFromSocket() { //if (!connect()) //{ // return; //} //原始人处理方式 // char szMsg[4096] = {0}; // int ret = zmq_recv(socket,szMsg,4096,0); // if(ret <= 0) return QByteArray(); // QByteArray array; // array.append(szMsg,ret); //古代人处理方式 QByteArray ret; zmq_msg_t message; zmq_msg_init (&message); int length = zmq_msg_recv (&message,m_socket, 0); if (length > 0) { //发送消息 emit *** ret.append(reinterpret_cast<char *>(zmq_msg_data (&message)), length); TraceHandle::log_trace(__FILE__, __FUNCTION__, __LINE__, QString("Read: %1").arg(QString(ret))); emit msgRep(ret); // qDebug()<<"CMD Ret :"<<ret; } zmq_msg_close(&message); //现代人处理方式 // QByteArray ret; // while (true) { // zmq_msg_t message; // zmq_msg_init (&message); // int len = zmq_msg_recv (&message,socket, 0); // if(len <= 0) return QByteArray(); //wushuju huozhe cuowu // // 处理一帧消息 // ret.append(reinterpret_cast<char *>(zmq_msg_data (&message)) ,len); // zmq_msg_close (&message); // int64_t more = 0; // size_t more_size = sizeof (more); // zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size); // if (!more) // break; // 已到达最后一帧 // } } void ZmqSocket::run() { while(!m_stop){ //写消息 writeMsgToSocket(); //读消息 //readMsgFromSocket(); QThread::msleep(10); } if (nullptr != m_socket) { zmq_close(m_socket); m_socket = nullptr; } if (nullptr != m_ctx) { zmq_ctx_term(m_ctx); m_ctx = nullptr; } } 帮我优化ZMQ请求应答超时后,主线程UI卡顿的问题
最新发布
09-09
void g_pZmqCtx = zmq_ctx_new(); void pMsgSocket = zmq_socket(g_pZmqCtx, ZMQ_SUB); if (!pMsgSocket) { std::cout << “Failed to create message socket” << std::endl; return; } if (0 != zmq_connect(pMsgSocket, TEST_MSG_ADDR)) { std::cout << "Failed to connect the message socket! code = " << zmq_errno() << " reason = " << zmq_strerror(zmq_errno()) <<std::endl; } zmq_setsockopt(pMsgSocket, ZMQ_SUBSCRIBE, “”, 0); zmq_msg_t filter, frameHeader,imgData; zmq_msg_init(&filter); zmq_msg_init(&frameHeader); zmq_msg_init(&imgData); int nRecvLen = 0; while (true) { QApplication::processEvents(); nRecvLen = zmq_msg_recv(&filter, pMsgSocket, 0); if (nRecvLen < 0) { int err = zmq_errno(); printf(“Error: %s\n”, zmq_strerror(err)); std::cout << “Failed to receive filter” << std::endl; } else { nRecvLen = zmq_msg_recv(&frameHeader, pMsgSocket, 0); ((char)zmq_msg_data(&frameHeader))[nRecvLen] = ‘\0’; QJsonObject objData; QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson((char)zmq_msg_data(&frameHeader), &error); if (error.error != QJsonParseError::NoError) { qDebug() << “QJsonParseError” << error.errorString(); } objData = doc.object(); int nIndex = objData[“index”].toInt(); int nWidth = objData[“width”].toInt(); int nHeight = objData[“height”].toInt(); if (0 == std::string(static_cast<char*>(zmq_msg_data(&filter))).find(“RgbImg”)) { int nChannels = objData[“channels”].toInt(); nRecvLen = zmq_msg_recv(&imgData, pMsgSocket, 0); if (nRecvLen < 0) { std::cout << “Failed to receive message” << std::endl; } else { std::cout << "receive rgb data index : " << nIndex << std::endl; … … } } } } 优化这段代码
08-06
struct MotionData { string strFilter; std::vector<float>fPosition; uint32_t io_status; }; 2.3.1.2 Filter “motor” 2.3.1.3 Motor data name Type option desc io_status uint32_t required io status position vector<float> required frame width #define TEST_MOT_ADDR "tcp://127.0.0.1:9999" std::vector<double> result; motionData: void *g_pZmqCtx = zmq_ctx_new(); void *pMotSocket = zmq_socket(g_pZmqCtx, ZMQ_SUB); if (!pMotSocket) { std::cout << "Failed to create motor socket" << std::endl; return; } if (0 != zmq_connect(pMotSocket, TEST_ MOT _ADDR)) { std::cout << "Failed to connect the motor socket! code = " << zmq_errno() << " reason = " << zmq_strerror(zmq_errno()) <<std::endl; } zmq_setsockopt(pMotSocket, ZMQ_SUBSCRIBE, "", 0); zmq_msg_t filter,motData; zmq_msg_init(&filter); zmq_msg_init(&motData); int nRecvLen = 0; while (true) { QApplication::processEvents(); nRecvLen = zmq_msg_recv(&filter, pMotSocket, 0); if (nRecvLen < 0) { int err = zmq_errno(); printf("Error: %s\n", zmq_strerror(err)); std::cout << "Failed to receive filter" << std::endl; } else { nRecvLen = zmq_msg_recv(&motData, pMotSocket, 0); ((char*)zmq_msg_data(&motData))[nRecvLen] = '\0'; QJsonObject objData; QJsonParseError error; QJsonDocument doc = QJsonDocument::fromJson((char*)zmq_msg_data(&motData), &error); if (error.error != QJsonParseError::NoError) { qDebug() << "QJsonParseError" << error.errorString(); } objData = doc.object(); int io_status= objData["io_status "].toInt(); QJsonArray arr = obj.value("position").toArray(); for (const QJsonValue& val : arr) { result.push_back(val.toDouble()); } } } release: zmq_msg_close(&filter); 优化这段代码,将ZMQ订阅和解析消息封装在一个Qt的函数中
08-06
如果你需要在Java中使用ZeroMQ来处理大量数据,并且需要使用多进程,可以使用ZeroMQ的多线程/多进程模式,也称为"多路复用器"模式。 在这种模式下,你可以使用一个主进程来监听所有的ZeroMQ套接字,并将接收到的数据分发给多个子进程。每个子进程负责处理自己的数据,并将结果发送回主进程。 以下是一个使用Java ZeroMQ实现多路复用器的例子: ```java import org.zeromq.ZMQ; import org.zeromq.ZMQ.Context; import org.zeromq.ZMQ.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class MultiProcessZMQReceiver { public static void main(String[] args) { Context context = ZMQ.context(1); Socket frontend = context.socket(ZMQ.ROUTER); Socket backend = context.socket(ZMQ.DEALER); frontend.bind("tcp://*:5555"); backend.bind("inproc://backend"); ExecutorService executor = Executors.newFixedThreadPool(10); for (int i = 0; i < 10; i++) { executor.submit(new Worker()); } ZMQ.proxy(frontend, backend, null); frontend.close(); backend.close(); context.term(); } private static class Worker implements Runnable { @Override public void run() { Context context = ZMQ.context(1); Socket socket = context.socket(ZMQ.REP); socket.connect("inproc://backend"); while (!Thread.currentThread().isInterrupted()) { byte[] request = socket.recv(0); // process request here byte[] response = process(request); socket.send(response, 0); } socket.close(); context.term(); } private byte[] process(byte[] request) { // your processing logic here return request; } } } ``` 在这个例子中,我们使用一个ROUTER套接字作为前端套接字来接收所有的数据。然后,我们将所有数据转发到一个DEALER套接字中。DEALER套接字可以通过inproc协议与多个REP套接字通信。 我们启动了10个Worker线程来处理所有的REP套接字。每个Worker线程在自己的REP套接字上等待请求,并将请求传递给"process"方法进行处理。处理请求后,Worker线程将结果返回给REP套接字,然后等待下一个请求。 最后,我们使用ZMQ的proxy方法将所有的数据从前端套接字转发到后端套接字。当程序退出时,我们关闭所有的套接字并终止ZeroMQ上下文。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值