关于带有ZeroMQ的c ++:Qt发布订阅模式

Qt with ZeroMQ publish subscribe pattern

我想将ZeroMQ(4.1.2)与Qt(5.2.1)一起使用。
想法是拥有zmq pub / sub(服务器在外部),而sub是qt app。
目前在Qt应用中收到一次运行,有人可以删除提示吗?
是否可以通过其他方式实现ZeroMQ接收器?

目前,我的代码如下:

主窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

    void readZMQData();

private:
    Ui::MainWindow *ui;
    QSocketNotifier *qsn;
    void *context;
    void *subscriber;

};

主窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    /***** ZMQ *****/

    context = zmq_ctx_new ();
    subscriber = zmq_socket (context, ZMQ_SUB);
    int rc = zmq_connect (subscriber,"tcp://localhost:5556");

    char *filter ="";
    rc = zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE,filter, strlen (filter));
    unsigned int fd=0;
    size_t fd_size = sizeof(fd);
    rc = zmq_getsockopt(subscriber,ZMQ_FD,&fd,&fd_size);

    qsn = new QSocketNotifier(fd, QSocketNotifier::Read, this);
    connect(qsn, SIGNAL(activated(int)), this, SLOT(readZMQData()), Qt::DirectConnection);

}

MainWindow::~MainWindow()
{
    zmq_close (this->subscriber);
    zmq_ctx_destroy (this->context);
    delete ui;
}


void MainWindow::readZMQData()
{
    qsn->setEnabled(false);
    qDebug() <<"Got data!";

    int events = 0;
    std::size_t eventsSize = sizeof(events);
    zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
    if(events & ZMQ_POLLIN){
        qDebug() <<" ======  Data to read ======";

        char *string = s_recv(subscriber);
        qDebug() <<"DATA:" << string;
        free(string);
    }

    qsn->setEnabled(true);
}

服务器应用程序是(来自ZeroMQ示例):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include"zhelpers.h"

int main (void)
{
    //  Prepare our context and publisher
    void *context = zmq_ctx_new ();
    void *publisher = zmq_socket (context, ZMQ_PUB);
    int rc = zmq_bind (publisher,"tcp://*:5556");
    assert (rc == 0);

    //  Initialize random number generator
    srandom ((unsigned) time (NULL));
    while (1) {
        //  Get values that will fool the boss
        int zipcode, temperature, relhumidity;
        zipcode     = randof (100000);
        temperature = randof (215) - 80;
        relhumidity = randof (50) + 10;

        //  Send message to all subscribers
        char update [20];
        sprintf (update,"%05d %d %d", zipcode, temperature, relhumidity);
        s_send (publisher, update);
    }
    zmq_close (publisher);
    zmq_ctx_destroy (context);
    return 0;
}

第一个帮助的tnx,

我发现了问题,当ZeroMQ通知有消息要读取时,您需要全部读取它们,而不仅仅是第一条。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    void MainWindow::readZMQData(int fd)
{
    qsn->setEnabled(false);

    int events = 0;
    std::size_t eventsSize = sizeof(events);
    zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
    if(events & ZMQ_POLLIN){
        qDebug() <<" ======  Data to read ======";

        char *string;
        // THIS IS THE TRICK! READ UNTIL THERE IS MSG
        while((string = s_recv_nb(subscriber)) != NULL){
            qDebug() <<"DATA:" << string;
            free(string);
        }
    }

    qsn->setEnabled(true);
}


套接字通知程序看起来应该可以工作。 您是否已阅读有关正确处理文档的文档? 尤其是如果您使用的是Windows,则在进行读取...禁用,读取等操作时,似乎有特殊的处理方法。

http://doc.qt.io/qt-5/qsocketnotifier.html#details

希望能有所帮助。


由于尚不清楚s_recv_nb(zmq::socket_t & socket)是什么,我将提供-稍微详细一点的实现-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
      void MainWindow::readZMQData()
      {
       qsn->setEnabled(false);

       int events = 0;
       std::size_t eventsSize = sizeof(events);
       zmq_getsockopt(subscriber,ZMQ_EVENTS, &events, &eventsSize);
       if(events & ZMQ_POLLIN){
       qDebug() <<" ======  Data to read ======";

       char *string;
       int64_t more;
       size_t more_size = sizeof (more);

       do {
           /* Create an empty ?MQ message to hold the message part */
           zmq_msg_t part;
           int rc = zmq_msg_init (&part);
           assert (rc == 0);
           rc = zmq_msg_recv (&part, subscriber, 0);
           assert (rc != -1);
           /* Determine if more message parts are to follow */
           rc = zmq_getsockopt (subscriber, ZMQ_RCVMORE, &more, &more_size);
           assert (rc == 0);
           string = (char*) zmq_msg_data(&part);
           qDebug() << QString(string) ; // <<"more" << more;

           zmq_msg_close (&part);
          } while (more);
       }

       qsn->setEnabled(true);
     }

还有一点要注意:在Windows 64的情况下,当传递ZMQ_FD option_val的本地地址时,文件描述符fd应该为uint64_t,如zmq_getsockopt在Windows x64上返回EINVAL