2015-07-15 8 views
2

Я хотел бы использовать ZeroMQ (4.1.2) с Qt (5.2.1). Идея состоит в том, чтобы иметь zmq pub/sub (где сервер снаружи), а sub - qt app. В настоящее время получать в приложении Qt запускается один раз, может кто-то сбросить подсказку? Должен ли приемник ZeroMQ каким-то другим способом?Qt с ZeroMQ опубликовать шаблон подписки

В настоящее время мой код выглядит следующим образом:

mainwindow.h

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; 

}; 

mainwindow.cpp

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):

#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; 
} 

ответ

1

Извещатель сокета выглядит так, как будто он должен работать. Вы читали документы по правильному обращению? Особенно, если вы на Windows, похоже, есть специальные способы, чтобы справиться с этим, делая чтение ... отключение, чтение и т.д.

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

Надежда, что помогает.

3

Первый Тпх за помощь,

Я нашел этот вопрос, когда ZeroMQ уведомляет, что есть сообщение, чтобы прочитать вам нужно прочитать их все, а не только первый.

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); 
} 
+0

Не могли бы вы предоставить полный рабочий пример, пожалуйста, – dlewin

+0

ваш код дублируется: вы предоставляете 2 контекста – dlewin

0

Как это не ясно, что s_recv_nb(zmq::socket_t & socket), я приведу мой - немного подробнее - реализация в:

 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 дескрипторов файлов fd должен be uint64_t как в zmq_getsockopt returns EINVAL on windows x64 when local address of ZMQ_FD option_val passed