java和zmq多线程,Qt使用ZMQ进行多线程发布订阅

知识点涉及:1, Qt多线程编程

2, ZMQ使用发布订阅模式通信

使用python 写zmq 发布订阅, https://www.cnblogs.com/yezl/p/6604680.html点击打开链接

.h

#ifndef ZMQMANAGER_H

#define ZMQMANAGER_H

#include

#include "zmq.h"

/************************************************************

*description : 通信管理类,应用zmq 发布订阅模式,zmq 版本:zmq 4.0.4, vs2015

*author : gyh

*date : 2018/5/4 11:24

*last change :

*************************************************************/

class Publisher;

class SubScriber;

class ZMQManager : public QObject

{

Q_OBJECT

public:

ZMQManager(QObject *parent = nullptr);

~ZMQManager();

void sendData(const QByteArray &ba);

signals:

void sigSendData(const QByteArray &ba);

void sigRun();

public slots:

void slotRecv(int cmd, const QString &status);

private:

Publisher * m_pub;

SubScriber * m_sub;

};

/************************************************************

*description : 发布端

*author : gyh

*date : 2018/5/3 17:02

*last change :

*************************************************************/

class Publisher : public QObject

{

Q_OBJECT

public:

Publisher(QObject * parent = nullptr);

~Publisher();

void initZMQ();

// 发送数据

void sendData(const QByteArray &ba);

private:

void * m_context;

void * m_publisher; //发布者

};

/************************************************************

*description : 订阅端

*author : gyh

*date : 2018/5/3 17:02

*last change :

*************************************************************/

class SubScriber : public QObject

{

Q_OBJECT

public:

SubScriber(QObject * parent = nullptr);

~SubScriber();

void initZMQ();

void recv(); //接收

signals:

void sigRecv(int cmd, const QString &status);

private:

void * m_context;

void * m_subscriber; //订阅者

};

#endif // ZMQMANAGER_H

.cpp

#include "zmqmanager.h"

#include "share/lkQDebug.h"

#include

#include

#include

ZMQManager::ZMQManager(QObject *parent)

: QObject(parent)

{

QThread * pubThread = new QThread;

m_pub = new Publisher;

m_pub->moveToThread(pubThread);

pubThread->start();

connect(this, &ZMQManager::sigSendData, m_pub, &Publisher::sendData);

QThread * subThread = new QThread;

m_sub = new SubScriber;

m_sub->moveToThread(subThread);

subThread->start();

connect(m_sub, &SubScriber::sigRecv, this, &ZMQManager::slotRecv);

connect(this, &ZMQManager::sigRun, m_sub, &SubScriber::recv);

}

ZMQManager::~ZMQManager()

{

}

void ZMQManager::sendData(const QByteArray &ba)

{

DBG_LOG(11, QStringLiteral("主线程%1 发送数据").arg((int)QThread::currentThreadId()));

sigSendData(ba);

}

void ZMQManager::slotRecv(int cmd, const QString &status)

{

DBG_LOG(11, QStringLiteral("主线程%1 收到数据 %2 %3").arg((int)QThread::currentThreadId()).arg(cmd).arg(status));

}

//

Publisher::Publisher(QObject * parent /*= nullptr*/)

:QObject(parent)

{

initZMQ();

}

Publisher::~Publisher()

{

zmq_close(m_publisher); //关闭发布者

zmq_ctx_destroy(m_context); //释放发布者上下文

}

void Publisher::initZMQ()

{

m_context = zmq_ctx_new(); //创建zmq上下文

m_publisher = zmq_socket(m_context, ZMQ_PUB); //创建发布端套接字,非线程安全

int rc = zmq_bind(m_publisher, "tcp://*:6666"); //绑定端口6666

assert(rc == 0);

}

void Publisher::sendData(const QByteArray &ba)

{

int ret = zmq_send(m_publisher, ba.data(), ba.size(), 0); //发布固定内存数据

DBG_LOG(11, QStringLiteral("发布线程 %1, 发送数据 %2 字节").arg((int)QThread::currentThreadId()).arg(ret));

}

//

SubScriber::SubScriber(QObject * parent /*= nullptr*/)

: QObject(parent)

{

initZMQ();

}

SubScriber::~SubScriber()

{

zmq_close(m_subscriber); //关闭订阅端

zmq_ctx_destroy(m_context); //释放订阅端上下文

}

void SubScriber::initZMQ()

{

m_context = zmq_ctx_new(); //创建订阅端上下文

m_subscriber = zmq_socket(m_context, ZMQ_SUB); //创建订阅端套接字

int rc = zmq_connect(m_subscriber, "tcp://localhost:6666"); //连接端口6666

assert(rc == 0);

if (rc == -1)

{

int err = zmq_errno();

DBG_LOG(11, QString("connect error %1").arg(err));

return;

}

/*zmq_setsockopt()函数会对socket参数指定的socket进行设置,

设置的属性由option_name参数指定,属性值由参数option_value指定。

option_len参数指定属性值的数据存储空间的大小

option: 查看函数翻译文档 https://www.cnblogs.com/fengbohello/p/4398953.html

*/

int ret = zmq_setsockopt(m_subscriber, ZMQ_SUBSCRIBE, NULL, 0);

}

void SubScriber::recv()

{

int size = 0;

int cmdCode;

char buffer[256];

int nbytes = 0;

int offset = 0;

forever

{

// zmq_recv (void *s, void *buf, size_t len, int flags)

// zmq_recv()函数会从socket参数指定的socket上接收一个消息,

//并把这个消息存储在buf参数指定的内存空间中。超过len参数指

//定长度的任何数据都会被删去。如果在socket上没有消息可接收,

//zmq_recv()函数会进行阻塞,直到请求被满足为止。flag参数是由下面的选项组合而成的标志。

//ZMQ_DONTWAIT:此函数在非阻塞模式下执行

//Multi-part:一个ZMQ消息由1个或多个ZMQ消息帧组成

memset(buffer, 0, 256 * sizeof(char));

nbytes = zmq_recv(m_subscriber, &buffer, 256, 0);

if (nbytes == -1) {

qDebug() << "receiver cmd null , continue";;

continue;

}

DBG_LOG(11, QStringLiteral("订阅线程%1 , 收到数据 %2字节").arg((int)QThread::currentThreadId()).arg(nbytes));

memcpy(&cmdCode, buffer + offset, 4); offset += 4;

memcpy(&size, buffer + offset, 4); offset += 4;

switch (cmdCode)

{

case 1001:

{

QString state(buffer+offset);

DBG_LOG(11, QStringLiteral("收到命令%1, 状态%2").arg(cmdCode).arg(state));

sigRecv(cmdCode, state);

}

break;

default:

break;

}

}

}

main

#include "zmqmanager.h"

#include

#include

#include

int main(int argc, char *argv[])

{

QApplication a(argc, argv);

a.setOrganizationDomain("WYX");

a.setApplicationName("ExamTeacher");

//服务器IP

QSettings confSetting(DIR_CONFIG + "conf_teacher.ini", QSettings::IniFormat);

QString address = confSetting.value("SERVER/IP").toString();

int port = confSetting.value("SERVER/Port", 6379).toInt();

#ifdef __TEST__

ZMQManager zmqManager;

zmqManager.sigRun();

QTimer::singleShot(1000, &zmqManager, [&]() {

int cmd = 1001;

int size = 128;

const char * state = "connected";

QByteArray ba;

ba.append((char*)&cmd, sizeof(cmd));

ba.append((char*)&size, sizeof(size));

ba.append(state, 128);

int n = ba.size();

zmqManager.sendData(ba);

});

#endif

#ifdef __TEST__

//w.startRedis();

//w.show();

//#else

ExamLogin * login = new ExamLogin(&w);

login->exec();

#endif

return a.exec();

}

0818b9ca8b590ca3270a3433284dd417.png

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值