PDA

View Full Version : ZeroMQ with Qt client socket



ashboi
10th October 2013, 07:58
I've recently started on a project which requires me to write a script in order to send/receive strings on the pc, in which I've decided and written a piece of code to allow the pc to communicate using zeromq in a qt app that I'm currently building. However, I'm facing some issues with the zeromq bindings (nzmqt) for qt and the client (pc side) can't seem to connect to the server address/port(a separate device on the same network). After numerous attempts to debug it, I can't seem to find out what have I done wrong, and the scarce amount of documentation for the bindings aren't really helping much either. The pc app compiles without errors and is able to run, but the sockets aren't connecting at all. I was hoping that someone might have done something similar and could assist on this issue of mine.

socket.cpp

#include "socket.h"
#include <QByteArray>
#include <QList>
#include <QSignalSpy>

nzmqt::Socket::Socket(QObject* parent) :
QThread(parent)
{
m_address = "tcp://127.0.0.1:8887";
ZMQContext* context = createDefaultContext(this);
context->start();

m_socket = context->createSocket(ZMQSocket::TYP_PUSH);
connect(m_socket, SIGNAL(connected()), SLOT(sendString()));

r_address = "tcp://127.0.0.1:8886";
r_socket = context->createSocket(ZMQSocket::TYP_SUB);
connect(r_socket, SIGNAL(recvString(const QList<QByteArray>&)), SLOT(recvString(const QList<QByteArray>&)));

timerout = new QTimer(this);
timerout->setInterval(2500);
timerout->setSingleShot(true);

connect(timerout, SIGNAL(timeout()), this, SLOT(timerout_timeout()));

client = new nzmqt::Socket(this);
client->start();

}

nzmqt::Socket::~Socket()
{
client->stop();
}

void nzmqt::Socket::run()
{
m_socket->connectTo(m_address); //send
r_socket->connectTo(r_address); //feedback

timerout->start();
this->exec();
}

void nzmqt::Socket::stop()
{
timerout->stop();
m_socket->close();
this->quit();
}

void nzmqt::Socket::send(QString message) //taking an emitted string from a button on the app
{
this->message = message;
}

void nzmqt::Socket::sendString()
{
m_socket->sendMessage(signal.toStdString().c_str());
emit socketStarted(signal);
QTimer::singleShot(0, this, SLOT(stop()));
}

void nzmqt::Socket::recvString(const QList<QByteArray>& message) //print feedback
{
qDebug() << message;
}


socket.h

#ifndef SOCKET_H
#define SOCKET_H

#include <nzmqt/nzmqt.hpp>

#include <QByteArray>
#include <QDateTime>
#include <QList>
#include <QTimer>
#include <QThread>

namespace nzmqt
{

class Socket : public QThread
{
Q_OBJECT

public:
Socket(QObject *parent=0);
~Socket();
void run();

public slots:
void stop();
void sendString();
void send(QString message);

signals:
void socketStarted(QString signal);

protected slots:
void recvString(const QList<QByteArray>& message);

private:
QString message;
QString m_address;
QString r_address;

ZMQSocket* m_socket;
ZMQSocket* r_socket;
QTimer* timerout;
Socket *client;
};
}
#endif // SOCKET_H

anda_skoa
11th October 2013, 10:38
One problem is that you create a QTimer in the context of the caller thread (constructor) but try to access it in the context of the worker thread (run).
You should also be aware that you are connecting it to a slot that belongs to an object in the caller thread, so it will be executed by the caller thread. Not sure if this is what you intend to happen.

Since threads tend to make everything more complicated, have you tried doing it without threads first?

Cheers,
_

ashboi
13th October 2013, 09:07
I haven't tried without threads yet, but I've gotten my client socket working. However, I was wondering how should I modify my codes in a such a way that the when the app runs, the socket waits until a signal(string) is emitted from a pushbutton(on another form), and proceed to send this string over to the server, and continue to wait until another signal has been emitted/received.

I'm quite new in working with Qt, but I currently got the signal to emit the correct strings on another form (form B), and the socket is running in main.cpp, I can't seem to receive the emitted signals on my socket thread. I've tested by starting the socket thread in form B instead of main.cpp, I can receive the signals but it doesn't wait indefinitely initially until the button is clicked(since Qtimer is set at 1000ms), and after sending the strings, it doesn't wait again until another signal is received from the same pushbutton. I really hope someone could assist me on this.

socket.cpp

#include "socket.h"
#include <QByteArray>
#include <QList>
#include <QSignalSpy>

using namespace nzmqt;

Socket::Socket(QObject* parent) :
QThread(parent)
{
m_address = "tcp://127.0.0.1:8887";
ZMQContext* context = createDefaultContext(this);
context->start();

m_socket = context->createSocket(ZMQSocket::TYP_PUSH);

topic_ = "";
r_address = "tcp://127.0.0.1:8888";
r_socket = context->createSocket(ZMQSocket::TYP_SUB);
connect(r_socket, SIGNAL(messageReceived(const QList<QByteArray>&)), SLOT(messageReceived(const QList<QByteArray>&)));

timerout = new QTimer(this);
timerout->setInterval(2500);
timerout->setSingleShot(true);

}

Socket::~Socket()
{
client->stop();
}

void Socket::run()
{
m_socket->connectTo(m_address);
QTimer::singleShot(1000, this, SLOT(sendMessage()));

r_socket->subscribeTo(topic_);
r_socket->connectTo(r_address);

timerout->start();
this->exec();
}

void Socket::stop()
{
timerout->stop();
m_socket->close();
this->quit();
}

void Socket::send(QString message) //received emitted signal
{
this->message = message;
}

void Socket::sendMessage() //send string
{
QList< QByteArray > msg;
msg+= message.toLocal8Bit(); //testing
m_socket->sendMessage(msg);
qDebug() << msg; //for testing
emit stringSent(msg);
QTimer::singleShot(0, this, SLOT(stop()));
}

void Socket::messageReceived(const QList<QByteArray>& message) //display feedback
{
qDebug() << message;
}



socket.h

#ifndef SOCKET_H
#define SOCKET_H

#include <nzmqt/nzmqt.hpp>

#include <QByteArray>
#include <QDateTime>
#include <QList>
#include <QTimer>
#include <QObject>
#include <QThread>

namespace nzmqt
{

class Socket : public QThread
{
Q_OBJECT

public:
Socket(QObject *parent=0);
~Socket();
void run();

public slots:
void stop();
void send(QString message); //receive emitted signal

signals:
void stringSent(const QList<QByteArray>& message);


protected slots:
void messageReceived(const QList<QByteArray>& message);
void sendMessage();

private:
QString message;
QString m_address;
QString r_address;
QString r_address1;
QString topic_;

ZMQSocket* m_socket;
ZMQSocket* r_socket;
ZMQSocket* r_socket1;
QTimer* timerout;
Socket *client;
};
}
#endif // SOCKET_H

anda_skoa
13th October 2013, 09:59
I would strongly suggest to make it work in a single threaded context first.

It avoids all kinds of mistakes, e.g, creating a timer in one thread and starting/stopping it from another (like you do with timerout) or making wrong assumption about thread context in slots (you might think that sendMessage() is called by the socket thread).

Once you have it running in a single thread it is way easier to move it into a thread and just to deal with the necessary changes then, instead of trying everything in one go.
Especially when being new to multithreading with Qt

Cheers,
_