Use QT to read from socket - c++

I want to use IPC in order to exchange messages between two separate applications. The first one is a BASH script which is fired when a specific udev rule is activated (in Ubuntu Linux), and the other one is a simple Qt 5.7 console application, which acts as a server.
I already have the Qt server working and printing a message when it accepts a connection to the specified socket. What I'm trying to achieve now, is to make the server do something not when it accepts a connection, but when it receives a certain "message". Any ideas on how to do it?
Below is my code:
server.cpp
#include "server.h"
Server::Server() : QThread()
{
m_server = new QLocalServer(this);
m_server->listen("somesocket.sock");
connect(m_server, &QLocalServer::newConnection, this, &Server::testFunction);
}
Server::~Server()
{
m_server->removeServer("somesocket.sock");
}
void Server::run()
{
}
void Server::testFunction(){
qDebug() << "Sth happened!";
return;
}
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QThread>
#include <QObject>
#include <QDebug>
#include <QLocalServer>
class Server : public QThread
{
public:
Server();
~Server();
void run();
void testFunction();
private:
QLocalServer *m_server;
signals:
void connectionEstablished(bool);
};
#endif // SERVER_H

You could connect to readyRead signal, and then check received message, like in this example:
connect( this, SIGNAL(readyRead()), SLOT(readClient()) );
void readClient()
{
QTextStream ts( this );
int line = 0;
while ( canReadLine() ) {
QString str = ts.readLine();
if(str == "someSpecialMessage")
{
//...
}
line++;
}
}
for more informations about this signal, see documentation: http://doc.qt.io/qt-5/qiodevice.html#readyRead
This is also an example of client and server applications in Qt, using QSocket and QServerSocket: https://doc.qt.io/archives/3.3/clientserver-example.html

Related

QTcpSocket fails to transmit data when reconnecting to server after RemoteHostClosedError

See EDIT1 at the end of the question for a possible solution - It would be great if somebody could comment on my interpretation, so that I can understand better what's happening
I'm writing a simple TCP client, based on QTcpSocket and managed by a QStateMachine (connect to server -> transmit data -> if disconnected for any reason, reconnect to server).
I noticed that if the connection is shut down on the server side (client is notified with RemoteHostClosedError), after reconnection the QTcpSocket write() method succeeds but no data is transmitted on the wire - nothing is received by the server, and the bytesWritten() signal on the client side does not fire up.
I found in the documentation for error() signal (https://doc.qt.io/qt-5/qabstractsocket.html#error) that
When this signal is emitted, the socket may not be ready for a reconnect attempt. In that case,
attempts to reconnect should be done from the event loop".
I think I'm already ok with that, as the reconnection happens in one of the QStateMachine states, and QStateMachine should have its own event loop according to the QT docs.
Below some simplified code to reproduce the issue (sorry, not so minimal but I could not find a simpler way to show the problem):
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
#include <QTcpSocket>
#include <QDebug>
#include <QStateMachine>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
void onfsmTransmitExited();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
private:
void createClientFsm(); // Create client FSM
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QThread> // Sleep
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, SIGNAL(entered()), this, SLOT(onfsmConnectEntered()));
connect(sTransmit, SIGNAL(entered()), this, SLOT(onfsmTransmitEntered()));
// Add exit actions to states
connect(sTransmit, SIGNAL(exited()), this, SLOT(onfsmTransmitExited()));
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::onfsmConnectEntered()
{
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// Wait for connection result
if(!m_socket->waitForConnected(10000))
{
qDebug() << "Error: " << m_socket->errorString();
emit fsmEvtError();
}
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}
void TestClient::onfsmTransmitExited()
{
qDebug() << "waiting before reconnection attempt...";
QThread::sleep(2);
}
main.cpp
#include <QCoreApplication>
#include "testclient.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TestClient client(&a);
client.start();
return a.exec();
}
To test, you can just launch netcat (nc -l -p 11000) , then close the nc process after receiving TEST MESSAGE and finally relaunch it again. The second time, TEST MESSAGE is not received, and we don't have the onSocketBytesWritten() printout, see below:
connecting...
connected...
sending data...
12 bytes written... <<<<<<<<<< Correct transmission, event fires up
socket error QAbstractSocket::RemoteHostClosedError
disconnected...
waiting before reconnection attempt...
connecting...
connected...
sending data... <<<<<<<<<< No transmission, event does not fire up, no socket errors!
EDIT1: I found out that if I create the QTcpSocket on connection and destroy it on disconnection, the problem does not happen. Is this the expected/proper way to use sockets?
Wouldn't it be possible instead to create the socket just once and just connect/disconnect? Maybe it is just a matter of flushing or cleaning up in a specific manner, but I could not find it so far.
Here are the modifications that make the code above work on server-side disconnection:
Move socket creation from class constructor to onfsmConnectEntered() - handler for entry in the "Connect" QState:
void TestClient::onfsmConnectEntered()
{
m_socket = new QTcpSocket(this);
connect(m_socket, SIGNAL(connected()),this, SLOT(onSocketConnected()));
connect(m_socket, SIGNAL(disconnected()),this, SLOT(onSocketDisconnected()));
connect(m_socket, SIGNAL(bytesWritten(qint64)),this, SLOT(onSocketBytesWritten(qint64)));
connect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(onSocketError(QAbstractSocket::SocketError)));
qDebug() << "connecting...";
m_socket->connectToHost("localhost", 11000);
// The rest of the method is the same
}
Delete the socket on disconnection, so that it is deallocated and will be created again on reconnection:
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
m_socket->deleteLater();
m_socket = nullptr;
emit fsmEvtError();
}
Do not use waitForX methods as they block the event loop and prevent them from using that resource as the signals do not do their job correctly or the QStateMachine.
Considering the above, the solution is:
void TestClient::onfsmConnectEntered()
{
m_socket->connectToHost("localhost", 11000);
}
But even so your code has errors since it does not consider other cases such as:
If when you start the client the server is not running, your application will try to connect the error will be launched and nothing else.
If the server fails for a longer time than the 10000 ms timeout set to waitForConnected(), the same will happen as in the previous case.
Then the idea is to try to connect until you are sure of the connection and that can be done through a QTimer with an appropriate period.
testclient.h
#ifndef TESTCLIENT_H
#define TESTCLIENT_H
#include <QObject>
class QTcpSocket;
class QStateMachine;
class QTimer;
#include <QAbstractSocket>
class TestClient : public QObject
{
Q_OBJECT
public:
explicit TestClient(QObject *parent = nullptr);
public slots:
void start();
signals:
// FSM events
void fsmEvtConnected();
void fsmEvtError();
private slots:
void onSocketConnected(); // Notify connection to TCP server
void onSocketDisconnected(); // Notify disconnection from TCP server
void onSocketBytesWritten(qint64 bytes); // Notify number of bytes written to TCP server
void onSocketError(QAbstractSocket::SocketError err);
// FSM state enter/exit actions
void onfsmConnectEntered();
void onfsmTransmitEntered();
private:
// Member variables
QTcpSocket* m_socket; // TCP socket used for communications to server
QStateMachine* m_clientFsm; // FSM defining general client behaviour
QTimer* m_timer;
private:
void createClientFsm(); // Create client FSM
void tryConnect();
};
#endif // TESTCLIENT_H
testclient.cpp
#include "testclient.h"
#include <QState>
#include <QStateMachine>
#include <QTcpSocket>
#include <QThread> // Sleep
#include <QTimer>
//-----------------------------------------------------------------------------
// PUBLIC METHODS
//-----------------------------------------------------------------------------
TestClient::TestClient(QObject *parent) : QObject(parent)
{
m_socket = new QTcpSocket(this);
m_timer = new QTimer(this);
m_timer->setInterval(100);
connect(m_timer, &QTimer::timeout, this, &TestClient::tryConnect);
connect(m_socket, &QAbstractSocket::connected,this, &TestClient::onSocketConnected);
connect(m_socket, &QAbstractSocket::disconnected,this, &TestClient::onSocketDisconnected);
connect(m_socket, &QIODevice::bytesWritten,this, &TestClient::onSocketBytesWritten);
connect(m_socket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error), this, &TestClient::onSocketError);
}
void TestClient::start()
{
createClientFsm();
m_clientFsm->start();
}
//-----------------------------------------------------------------------------
// TCP CONNECTION MANAGEMENT SLOTS
//-----------------------------------------------------------------------------
void TestClient::onSocketConnected()
{
m_timer->stop();
qDebug() << "connected...";
emit fsmEvtConnected();
}
void TestClient::onSocketDisconnected()
{
qDebug() << "disconnected...";
emit fsmEvtError();
}
void TestClient::onSocketBytesWritten(qint64 bytes)
{
qDebug() << bytes << " bytes written...";
}
void TestClient::onSocketError(QAbstractSocket::SocketError err)
{
qDebug() << "socket error " << err;
}
//-----------------------------------------------------------------------------
// FSM MANAGEMENT
//-----------------------------------------------------------------------------
void TestClient::createClientFsm()
{
m_clientFsm = new QStateMachine(this);
// Create states
QState* sConnect = new QState();
QState* sTransmit = new QState();
// Add transitions between states
sConnect->addTransition(this, SIGNAL(fsmEvtConnected()), sTransmit);
sTransmit->addTransition(this, SIGNAL(fsmEvtError()), sConnect);
// Add entry actions to states
connect(sConnect, &QAbstractState::entered, this, &TestClient::onfsmConnectEntered);
connect(sTransmit, &QAbstractState::entered, this, &TestClient::onfsmTransmitEntered);
// Create state machine
m_clientFsm->addState(sConnect);
m_clientFsm->addState(sTransmit);
m_clientFsm->setInitialState(sConnect);
}
void TestClient::tryConnect(){
m_socket->connectToHost("localhost", 11000);
}
void TestClient::onfsmConnectEntered()
{
m_timer->start();
}
void TestClient::onfsmTransmitEntered()
{
qDebug() << "sending data...";
m_socket->write("TEST MESSAGE");
}

Qt5 (5.7) Websockets do not work on Windows Phone

Hello dear fellow programmers,
we try to write an application that will run on windows phone and android.
Part of this app ist to establish a secure connection to a websocket server, which does not work on the windows phone. Works however perfect under Linux.
//constructor opening connection
MeteorDDP::MeteorDDP(QString uri){
QUrl wsUri = QUrl("wss://"+uri+"/websocket");
qDebug()<<wsUri;
connect(&wsClient, &QWebSocket::textMessageReceived,this, &MeteorDDP::handleMessage);
connect(&wsClient, &QWebSocket::connected,this, &MeteorDDP::onConnected);
connect(&wsClient, &QWebSocket::stateChanged, this, &MeteorDDP::onStateChanged);
connect(&wsClient, static_cast<void(QWebSocket::*)(QAbstractSocket::SocketError)>(&QWebSocket::error),
[=](QAbstractSocket::SocketError error){
qDebug()<<error<<"error";
});
connect(&wsClient, &QWebSocket::sslErrors, this, &MeteorDDP::onSslError);
wsClient.open(wsUri);
wsClient.flush();
}
And a method which just should output connected:
void MeteorDDP::onConnected(){
qDebug()<<"connected";
}
H file:
#ifndef METEORDDP_H
#define METEORDDP_H
#include <QString>
#include <QHash>
#include <QUrl>
#include <QtWebSockets/QtWebSockets>
class MeteorDDP : public QObject
{
Q_OBJECT
public:
MeteorDDP(QString server);
protected:
QWebSocket wsClient;
void onConnected();
void onStateChanged(QAbstractSocket::SocketState state);
void onSslError(void);
void onError(QAbstractSocket::SocketError error);
}
Methods:
void MeteorDDP::onStateChanged(QAbstractSocket::SocketState state){
qDebug() <<state<<"state Changed";
}
void MeteorDDP::onError(QAbstractSocket::SocketError error){
qDebug()<<error <<"error";
}
void MeteorDDP::onSslError(){
qDebug() <<"ssl error";
}

unable to send message from client to server

I am writing a client server program that server is multi thread , The code compile without any error, but it doesn't show any message from client.
just it run up to the "qDebug() << " Client connected";"
Here is my code .I would be grateful if you can say where is the problem.
myclient.cpp
#include "myclient.h"
#include "QTcpsocket"
#include "QTcpServer"
#include "mainwindow.h"
#include "QHostAddress"
myclient::myclient(QObject* parent): QObject(parent)
{
}
void myclient::start(QString address, quint16 port)
{
QHostAddress LocalHost;
LocalHost.setAddress(address);
m_client.connectToHost(LocalHost, 6666);
QObject::connect(&m_client, SIGNAL(connected()),this, SLOT(startTransfer()));
}
void myclient::startTransfer()
{
m_client.write("Hello", 5);
}
mythread.cpp
#include "mythread.h"
#include "myserver.h"
mythread::mythread(QTcpSocket*, QObject *parent) :
QThread(parent)
{
}
void mythread::run()
{
qDebug() << " Thread started";
if (m_client)
{
connect(m_client, SIGNAL(connected()), this, SLOT(readyRead()), Qt::DirectConnection);
}
qDebug() << " Client connected";
exec();
}
void mythread::readyRead()
{
QByteArray Data = m_client->readAll();
qDebug()<< " Data in: " << Data;
m_client->write(Data);
}
void mythread::disconnected()
{
qDebug() << " Disconnected";
m_client->deleteLater();
exit(0);
}
myserver.cpp
#include "myserver.h"
#include "mythread.h"
myserver::myserver(QObject *parent) :
QObject(parent)
{
}
void myserver::startserver()
{
connect(&m_server,SIGNAL(newConnection()), this ,SLOT(newConnection()));
int port = 6666;
if(m_server.listen(QHostAddress::Any, port))
{
qDebug() << "Listening to port " ;
}
else
{
qDebug() << "Could not start server "<<m_server.errorString();
}
}
void myserver::newConnection()
{
m_client = m_server.nextPendingConnection();
qDebug() << " Connecting...";
mythread *thread = new mythread(m_client,this);
thread->start();
}
Documentation about nextPendingConnection() says:
Note: The returned QTcpSocket object cannot be used from another
thread. If you want to use an incoming connection from another thread,
you need to override incomingConnection().
So, you can't use that socket in another thread. As the docs say, you can subclass QTcpServer and override incomingConnection(), this method is invoked whenever a client tries to connect to your server.
incomingConnection() method provides a socket descriptor (just like regular file descriptors). And then you can pass that socket descriptor to another thread and create the QTcpSocket completely over there.
Inside that thread, you would need something like this:
QTcpSocket client = new QTcpSocket();
client.setSocketDescriptor(sockId);
// Now, you can use this socket as a connected socket.
// Make sure to connect its ready read signal to your local slot.
Once you get in newConnection the client is already connected, and you just need to start a thread that calls readAll and then replies.
There's no need to wait for a connected() signal again.
EDIT
The QSocket class is designed to work asynchronously on the main thread, based on events. From the documentation:
Warning: QSocket is not suitable for use in threads. If you need to uses sockets in threads use the lower-level QSocketDevice class.

Thread sending http request using Qt

I am trying to create a thread (HttpWorker) that when required wakes up and sends a http request. I would like this to be done in a single thread. I am using Qt for the implementation.
The way I thought i would do it is to have a class MyHttpWorker, move it to another thread, connect the slots/signals etc. Then on thread start I would use QNetworkAccessManager to call get requests. I would use QWaitCondition to pause the thread after the request has been sent and I would resume this thread whenever I need to send another one.
However, when I pause the httpworker thread, the FinishedSlot is not called at all. If I use the class to simply call one http request, it executes with no problem. So the problem is connected to QWaitCondition (or just freezing the threads in general).
I could simply create and destroy one worker and thread for each request I have, but I require to send lot of http requests, so I think this method would be way too consuming (creating threads and destroying them over and over).
I appreciate any help I can get.
Here is my code:
MyHttpWorker.h
#include <QNetworkReply>
#include <QDebug>
#include <QObject>
#include <QNetworkAccessManager>
#include <QThread>
#include <QWaitCondition>
#include <QMutex>
class MyHttpWorker : public QObject
{
Q_OBJECT
QNetworkAccessManager* nam;
QMutex syncPause;
QWaitCondition pauseCond;
public:
explicit MyHttpWorker(QObject *parent = 0);
void MyWake();
public slots:
void SetTheThread(QThread* thread);
void MyStart();
void finishedSlot(QNetworkReply* reply);
};
MyHttpWorker.cpp
MyHttpWorker::MyHttpWorker(QObject *parent) :
QObject(parent)
{
nam = new QNetworkAccessManager(this);
QObject::connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(finishedSlot(QNetworkReply*)));
}
void MyHttpWorker::finishedSlot(QNetworkReply* reply)
{
qDebug() << "Finished"; //This slot is never even reached, when i used QWaitCond...
if (reply->error() == QNetworkReply::NoError)
{
QByteArray bytes = reply->readAll();
QString string(bytes);
qDebug() << string;
}else
{
qDebug() << reply->errorString();
}
reply->deleteLater();
}
void MyHttpWorker::SetTheThread(QThread* thread){
QObject::connect(thread,SIGNAL(started()),this,SLOT(MyStart()));
}
void MyHttpWorker::MyWake(){
pauseCond.wakeAll();
}
void MyHttpWorker::MyStart(){
qDebug() << "Start" ;
while(true){
syncPause.lock();
qDebug() << "thread waiting...";
pauseCond.wait(&syncPause);
qDebug() << "thread resumed.";
syncPause.unlock();
//sending the actual request here
QNetworkRequest myRequest;
myRequest.setUrl(QUrl("http://www.google.com"));
nam->get(myRequest);
}
}
main.cpp
#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <myhttpworker.h>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//create the worker, thread and launch it... (worker is waiting by default)
MyHttpWorker* worker = new MyHttpWorker;
QThread* httpThread = new QThread;
worker->SetTheThread(httpThread);
worker->moveToThread(httpThread);
httpThread->start();
//try and send 5 requests ...
for(int i=0;i<5;i++){
qDebug() << "Unpausing";
QThread::currentThread()->msleep(1000);
worker->MyWake();
}
return a.exec();
}
don't create an infinite loop but let the even loop handle it:
void MyHttpWorker::MyWake()
{
QMetaObject::invokeMethod(this,"doSend");
//send to the event loop
}
// new slot
void MyHttpWorker::doSend(){
//sending the actual request here
QNetworkRequest myRequest;
myRequest.setUrl(QUrl("http://www.google.com"));
nam->get(myRequest);
}
//and remove the myStart and all that synchronisation
then when you want to stop it just send a quit to the thread. I suggest you also connect the finished signal of the thread to the deleteLater slot of MyHttpWorker

QObject: no such slot QThread::readyRead()

I am trying to figure out how to correctly use Qt TCP Sockets, as well as multithreading. I want, as a test project in support of something more complex but similar I will try in the future, to do the following: a simple application that either listens for exactly one incoming connection, or connects to a serversocket; next it prints everything it receives over that socket.
The situation where I connect to a serversocket (I use netcat with the -l option for this) works fine: everything netcat sends to my application is printed correctly. However, when I use my program to listen for that one incoming connection (generated by netcat), the connecting succeeds but then I get this runtime error:
QObject::connect: No such signal QThread::readyRead() in ..\QTcpTest\listener.cpp:8
Here is the entire code (don't mind the plain C I/O I use sometimes, I'll remove this later):
[ main.cpp ]
#include "peer.h"
#include <QCoreApplication>
#include <QThread>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static bool askIfServer();
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Peer *p;
int rval;
if (askIfServer())
p = new Peer;
else
p = new Peer(false);
rval = a.exec();
delete p;
return rval;
}
static bool askIfServer()
{
bool isServer;
char ibuf[BUFSIZ];
fputs("Choose \'host\' or \'join\': ", stderr);
fgets(ibuf, BUFSIZ, stdin);
ibuf[strlen(ibuf) - 1] = '\0';
fflush(stdin);
if (strcmp(ibuf, "host") == 0)
isServer = true;
else if (strcmp(ibuf, "join") == 0)
isServer = false;
else
{
fputs("Failure.\n", stderr);
exit(-1);
}
return isServer;
}
[ peer.h ]
#ifndef PEER_H
#define PEER_H
#include "listener.h"
#include <QObject>
#include <QThread>
#include <QtNetwork/QTcpSocket>
#include <QtNetwork/QTcpServer>
class Peer : public QObject
{
Q_OBJECT
public:
static const quint16 PORT = 5483;
explicit Peer(bool isHost = true, QString hostname = "localhost", QObject *parent = 0);
public slots:
void acceptPeer();
private:
bool _isHost;
QTcpServer *_server;
QTcpSocket *_socket;
QThread *_lThread;
Listener *_listener;
};
#endif // PEER_H
[ peer.cpp ]
#include "peer.h"
Peer::Peer(bool isHost, QString hostname, QObject *parent) :
QObject(parent),
_isHost(isHost)
{
if (_isHost)
{
_server = new QTcpServer;
connect(_server, SIGNAL(newConnection()), this, SLOT(acceptPeer()));
_server->listen(QHostAddress::Any, PORT);
}
else
{
_socket = new QTcpSocket;
connect(_socket, SIGNAL(hostFound()), this, SLOT(acceptPeer()));
_socket->connectToHost(hostname, PORT);
}
}
void Peer::acceptPeer()
{
disconnect(this, SLOT(acceptPeer()));
if (_isHost)
{
_socket = _server->nextPendingConnection();
delete _server;
_server = NULL;
}
_lThread = new QThread;
_listener = new Listener(_socket);
_listener->moveToThread(_lThread);
_lThread->start();
}
[ listener.h ]
#ifndef LISTENER_H
#define LISTENER_H
#include <iostream>
#include <QObject>
#include <QByteArray>
#include <QtNetwork/QTcpSocket>
using std::cout;
class Listener : public QObject
{
Q_OBJECT
public:
explicit Listener(QTcpSocket *socket, QObject *parent = 0);
public slots:
void acceptData();
private:
QTcpSocket *_socket;
};
#endif // LISTENER_H
[ listener.cpp ]
#include "listener.h"
Listener::Listener(QTcpSocket *socket, QObject *parent) :
QObject(parent),
_socket(socket)
{
// I guess this is where it goes wrong
connect(_socket, SIGNAL(readyRead()), this, SLOT(acceptData()), Qt::QueuedConnection);
}
void Listener::acceptData()
{
QByteArray data = _socket->readAll();
cout << data.constData();
}
The thing I do not get is that the error message claims that I try to connect some signal from QThread (and I clearly do not: see listener.cpp:8); even stranger is that this only happens when the socket is created by the QTcpServer instance, not in the other case. What am I missing?
EDIT: SOLVED
See my own answer.
I do not use an extra thread anymore (see comment). The problem was deleting the QTcpServer instance in Peer::acceptPeer(), once a connection was established. I thought that I could delete it because I only need that one socket QTcpServer::nextPendingConnection() returns. Apparently this is wrong, the socket is probably destroyed as well, leaving me with a rogue pointer (I think) crashing the program. Now I only call _server->pauseAccepting(); right after I get the socket, and all works fine.
Here is the change I've made:
void Peer::acceptPeer()
{
disconnect(this, SLOT(acceptPeer()));
if (_isHost)
{
_socket = _server->nextPendingConnection();
_server->pauseAccepting(); // no deletion
}
_listener = new Listener(_socket);
}