QTcpSocket communication in a thread - qt

I'm making two application : one is the server and one is the client. The server use QTcpServer and QThread to listen to client. The client use QThread to make a connection to server.
The server and the client successfully connected, but the problem is how to communicate data between them. On server side, I put a line to send a data to client using socket->write("hello") when a new client is connected, but the client didn't receive it. The "didn't receive" conjecture based on nothing written on calling QDebug on client side.
Also, I want to ask about how to make the client thread always ready to receive data from server but sometimes can be used to send data to server when a PushButton is used.
Any help will be appreciated.
client side main.cpp (using a widget)
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "tcpthread.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
TcpThread *tcpThread = new TcpThread(this);
connect(tcpThread, SIGNAL(finished()), tcpThread, SLOT(deleteLater()));
tcpThread->start();
}
client side tcpthread.h
#ifndef TCPTHREAD_H
#define TCPTHREAD_H
#include <QThread>
#include <QTcpSocket>
class TcpThread : public QThread
{
Q_OBJECT
public:
explicit TcpThread(QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
public slots:
void readyRead();
void disconnected();
private:
void processMessage(QByteArray message);
QTcpSocket *socket;
qintptr socketDescriptor;
QByteArray data;
};
#endif // TCPTHREAD_H
client side tcpthread.cpp
#include "tcpthread.h"
TcpThread::TcpThread(QObject *parent) :
QThread(parent)
{
}
void TcpThread::run()
{
qDebug() << "Thread started";
socket = new QTcpSocket();
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
socket->connectToHost("127.0.0.1",1234);
exec();
}
void TcpThread::readyRead()
{
data = socket->readAll();
while(!data.contains('\n'))
{
socket->waitForReadyRead();
data += socket->readAll();
}
int bytes = data.indexOf('\n')+1;
QByteArray message = data.left(bytes);
data = data.mid(bytes);
qDebug() << socketDescriptor << " : " << message;
processMessage(message);
}
void TcpThread::disconnected()
{
qDebug() << socketDescriptor << " disconnected";
socket->deleteLater();
exit(0);
}
void TcpThread::processMessage(QByteArray message)
{
qDebug() << message << " processed";
}
server side main.cpp
#include "tcpserver.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
TcpServer tcpServer;
tcpServer.startServer();
return a.exec();
}
server side tcpthread.h
#ifndef TCPTHREAD_H
#define TCPTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QDebug>
class TcpThread : public QThread
{
Q_OBJECT
public:
explicit TcpThread(qintptr ID, QObject *parent = 0);
void run();
signals:
void error(QTcpSocket::SocketError socketError);
public slots:
void readyRead();
void disconnected();
private:
void processMessage(QByteArray message);
QTcpSocket *socket;
qintptr socketDescriptor;
QByteArray data;
};
#endif // TCPTHREAD_H
server side tcpthread.cpp
#include "tcpthread.h"
TcpThread::TcpThread(qintptr ID, QObject *parent) :
QThread(parent)
{
this->socketDescriptor = ID;
}
void TcpThread::run()
{
qDebug() << "Thread started";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(this->socketDescriptor))
{
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()));
qDebug() << socketDescriptor << " connected";
socket->write("hello");
exec();
}
void TcpThread::readyRead()
{
data = socket->readAll();
while(!data.contains('\n'))
{
socket->waitForReadyRead();
data += socket->readAll();
}
int bytes = data.indexOf('\n')+1;
QByteArray message = data.left(bytes);
data = data.mid(bytes);
qDebug() << socketDescriptor << " : " << message;
processMessage(message);
//socket->write(data);
}
void TcpThread::disconnected()
{
qDebug() << socketDescriptor << " disconnected";
socket->deleteLater();
exit(0);
}
void TcpThread::processMessage(QByteArray message)
{
qDebug() << message << " processed";
}

Related

udp binded/connected but not datagram received

I am new to Qt, c++, recently I am trying to use UDP to receive data on my raspberrypi1 from another raspberrypi2 (multicast). I am able to bind both of them but I can't receive the data (nopendingdatagram). I wonder what I did wrong here. (As you might notice, the code below was taken from examples found online). Thank you in advanced for helping me.
// myudp.h
#ifndef MYUDP_H
#define MYUDP_H
#include <QObject>
#include <QUdpSocket>
class MyUDP : public QObject
{
Q_OBJECT
public:
explicit MyUDP(QObject *parent = 0);
//void HelloUDP();
signals:
public slots:
void readyRead();
private:
QUdpSocket *socket;
};
#endif // MYUDP_H
// myudp.cpp
#include "myudp.h"
MyUDP::MyUDP(QObject *parent) :
QObject(parent)
{
// create a QUDP socket
socket = new QUdpSocket(this);
bool result = socket->bind(QHostAddress("224.224.0.2"), 10002);
if(result)
{
qDebug() << "Socket Connected";
}
else
{
qDebug() << "Socket Not Connected";
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()));
}
void MyUDP::readyRead()
{
// when data comes in
bool data_pending = socket->hasPendingDatagrams();
qDebug() << data_pending;
if(data_pending)
{
QByteArray buffer;
buffer.resize(socket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
socket->readDatagram(buffer.data(), buffer.size(),
&sender, &senderPort);
qDebug() << "Message from: " << sender.toString();
qDebug() << "Message port: " << senderPort;
qDebug() << "Message: " << buffer;
}
else
{
qDebug() << "No data";
}
}
#include <QCoreApplication>
#include "myudp.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyUDP client;
client.readyRead();
return a.exec();
}
The result is as follows:
Socket Connected
false
No data

QWebEngine download restart after a reboot

I did an application to download softwares. It's works well with QWebengine.
For the second version, I need to implement the restart of the download after the application is turned off.
My goal is to get possible to restart the same download at the same status after a reboot.
Is it possible?
How to save the status of the current download in a file with WebEngineDownloadItem ?
Thank you for your help
This is how I did :
DownloaderWidget.hpp
#ifndef DOWNLOADERWIDGET_HPP
#define DOWNLOADERWIDGET_HPP
# include <QUrl>
# include <QApplication>
# include <QPushButton>
# include <QString>
# include <QWidget>
# include <QLabel>
# include <QVBoxLayout>
# include <QProgressBar>
# include "downloadermanager.hpp"
class DownloaderWidget : public QWidget
{
Q_OBJECT
public:
explicit DownloaderWidget(QWidget *parent = nullptr);
signals:
public slots:
void download(void);
void pause(void);
void resume(void);
private slots:
void progress(int percent);
private:
static QString const
URL;
QLabel *m_url;
QPushButton *m_start;
QPushButton *m_resume;
QPushButton *m_pause;
QProgressBar *m_status;
DownloaderManager *m_download_manager;
};
#endif // DOWNLOADERWIDGET_HPP
DownloaderManager.hpp
#ifndef DOWNLOADERMANAGER_HPP
#define DOWNLOADERMANAGER_HPP
# include <QUrl>
# include <QObject>
# include <QDebug>
# include <QNetworkAccessManager>
# include <QNetworkRequest>
# include <QNetworkReply>
# include <QFile>
# include <QByteArray>
# include <QStandardPaths>
class DownloaderManager : public QObject
{
Q_OBJECT
public:
explicit DownloaderManager(QObject *parent = nullptr);
signals:
void downloadComplete(void);
void progress(int const percentage);
public slots:
void download(QUrl const &url);
void pause();
void resume();
private slots:
void download(QNetworkRequest &request);
void finished();
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void error(QNetworkReply::NetworkError code);
private:
QNetworkAccessManager
*m_manager;
QNetworkRequest m_request;
QNetworkReply *m_reply;
QFile *m_file;
qint64 m_downloadSizeAtPause;
QString m_name;
QString get_file_name(QUrl const &url);
};
#endif // DOWNLOADERMANAGER_HPP
DownloaderWidget.cpp
#include "downloaderwidget.hpp"
QString const DownloaderWidget::URL = "My great URL";
DownloaderWidget::DownloaderWidget(QWidget *parent)
: QWidget(parent),
m_url(new QLabel(URL, this)),
m_start(new QPushButton("Start", this)),
m_resume(new QPushButton("Resume", this)),
m_pause(new QPushButton("Pause", this)),
m_status(new QProgressBar(this)),
m_download_manager(new DownloaderManager(this))
{
QVBoxLayout *main_layout = new QVBoxLayout(this);
m_status->setOrientation(Qt::Horizontal);
main_layout->addWidget(m_url);
main_layout->addWidget(m_status);
main_layout->addWidget(m_start);
main_layout->addWidget(m_pause);
main_layout->addWidget(m_resume);
QObject::connect(m_start, SIGNAL(clicked()), this, SLOT(download()));
QObject::connect(m_pause, SIGNAL(clicked()), this, SLOT(pause()));
QObject::connect(m_resume, SIGNAL(clicked()), this, SLOT(resume()));
QObject::connect(m_download_manager, SIGNAL(downloadComplete()), qApp, SLOT(quit()));
QObject::connect(m_download_manager, SIGNAL(progress(int)), this, SLOT(progress(int)));
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::download(void)
{
this->m_download_manager->download(QUrl(URL));
this->m_start->setEnabled(false);
this->m_pause->setEnabled(true);
}
void DownloaderWidget::pause()
{
this->m_download_manager->pause();
this->m_pause->setEnabled(false);
this->m_resume->setEnabled(true);
}
void DownloaderWidget::resume(void)
{
this->m_download_manager->resume();
this->m_pause->setEnabled(true);
this->m_resume->setEnabled(false);
}
void DownloaderWidget::progress(int percent)
{
this->m_status->setValue(percent);
}
DownloaderManager.cpp
#include "downloadermanager.hpp"
DownloaderManager::DownloaderManager(QObject *parent) :
QObject(parent),
m_manager(new QNetworkAccessManager(this)),
m_request(),
m_reply(nullptr),
m_file(nullptr),
m_downloadSizeAtPause(0),
m_name("")
{
}
QString DownloaderManager::get_file_name(QUrl const &url)
{
QStringList list = url.toString().split("/");
this->m_name = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/" + list[list.length() - 1];
return (this->m_name + ".download");
}
void DownloaderManager::download(QUrl const &url)
{
this->m_name = this->get_file_name(url);
qDebug() << "Download : file = " << this->m_name;
this->m_downloadSizeAtPause = 0;
this->m_request = QNetworkRequest(url);
this->m_file = new QFile(this->m_name);
this->m_file->open(QIODevice::ReadWrite | QIODevice::Append);
if (this->m_file->size() != 0)
this->resume();
else
this->download(this->m_request);
}
void DownloaderManager::pause(void)
{
qDebug() << "pause()";
if(this->m_reply == nullptr)
return;
QObject::disconnect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::disconnect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::disconnect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
this->m_reply->abort();
this->m_file->write(this->m_reply->readAll());
this->m_reply = nullptr;
}
void DownloaderManager::resume(void)
{
qDebug() << "resume()";
this->m_file->flush();
this->m_downloadSizeAtPause = this->m_file->size();
QByteArray rangeHeaderValue = "bytes=" + QByteArray::number(this->m_downloadSizeAtPause) + "-";
this->m_request.setRawHeader("Range",rangeHeaderValue);
this->download(this->m_request);
}
void DownloaderManager::download(QNetworkRequest &request)
{
qDebug() << "download( QNetworkRequest& request )";
this->m_reply = this->m_manager->get(request);
QObject::connect(this->m_reply, SIGNAL(finished()), this, SLOT(finished()));
QObject::connect(this->m_reply, SIGNAL(downloadProgress(qint64, qint64)),
this, SLOT(downloadProgress(qint64, qint64)));
QObject::connect(this->m_reply, SIGNAL(error(QNetworkReply::NetworkError)),
this, SLOT(error(QNetworkReply::NetworkError)));
}
void DownloaderManager::finished(void)
{
qDebug() << "finihsed";
this->m_file->rename(this->m_name + ".download", this->m_name);
this->m_file->close();
this->m_file = nullptr;
this->m_reply = nullptr;
emit downloadComplete();
}
void DownloaderManager::downloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
qDebug() << "Download Progress: Received=" << this->m_downloadSizeAtPause + bytesReceived <<": Total=" << this->m_downloadSizeAtPause + bytesTotal;
this->m_file->write(this->m_reply->readAll());
int percentage =
static_cast<int>((this->m_downloadSizeAtPause + bytesReceived) * 100 ) / (this->m_downloadSizeAtPause + bytesTotal);
qDebug() << percentage;
emit progress(percentage);
}
void DownloaderManager::error(QNetworkReply::NetworkError code)
{
qDebug() << "Error:" <<code;
}
main.cpp
#include <QApplication>
#include "downloaderwidget.hpp"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
DownloaderWidget downloader;
downloader.show();
return (app.exec());
}
I hope this piece of code will help some one in the same case than me Thank you

How to communicate Qt applications two-way

I want to create two-way communicate beetwen my Qt Apps. I want to use QProcess to do this. I'm calling sucesfully child app from root app and sending test data without any erro, but I can't recive any data in child app. I'll be gratefull for any help. I'm using Qt 4.7.1. Below my test code:
Root app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess(this);
process->start(myChildApp);
process->waitForStarted();
process->setCurrentWriteChannel(QProcess::StandardOutput);
process->write("Test");
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
QByteArray InterProcess::read()
{
QByteArray readBuffer = process->readAllStandardOutput();
return readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
}
void InterProcess::readyReadStandardOutput()
{
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
Child app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess();
process->setCurrentReadChannel(QProcess::StandardOutput);
connect( process, SIGNAL(readyRead()), this, SLOT(readyReadStandardOutput()));
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
process->waitForReadyRead(5000);
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
setText("REady error");
}
void InterProcess::readyReadStandardOutput()
{
setMessage("2");
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
setText(QString(error));
}
It's very hard to explain in one answer all mistakes, so just look at code and ask if you still got problems.
Here is example of using QProcess as IPC.
This is your main process, that creates additional process and connects to its signals
MyApplicaiton.h
#ifndef MYAPPLICATION_H
#define MYAPPLICATION_H
#include <QApplication>
class InterProcess;
class MyApplication : public QApplication {
Q_OBJECT
public:
MyApplication(int &argc, char **argv);
signals:
void mainApplicationSignal();
private slots:
void onInterProcessSignal();
private:
InterProcess *mProcess;
};
#endif // MYAPPLICATION_H
MyApplicaiton.cpp
#include "MyApplication.h"
#include "InterProcess.h"
MyApplication::MyApplication(int &argc, char **argv) : QApplication(argc, argv) {
mProcess = new InterProcess(this);
connect(mProcess, SIGNAL(interProcessSignal()),
this, SLOT(onInterProcessSignal()));
mProcess->start();
}
void MyApplication::onInterProcessSignal() {}
This is example implementation of your interProcess class:
InterProcess.h
class InterProcess : public QProcess {
Q_OBJECT
public:
explicit InterProcess(QObject *parent = nullptr);
signals:
void interProcessSignal();
private slots:
void onMainApplicationSignal();
};
InterProcess.cpp
#include "InterProcess.h"
#include "MyApplication.h"
InterProcess::InterProcess(QObject *parent) : QProcess(parent) {
if(parent) {
auto myApp = qobject_cast<MyApplication *>(parent);
if(myApp) {
connect(myApp, SIGNAL(mainApplicationSignal()),
this, SLOT(onMainApplicationSignal()));
}
}
}
void InterProcess::onMainApplicationSignal() {}
Locally, using UDP is very convenient and efficient
void Server::initSocket() {
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 7755);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));}
void Server::readPendingDatagrams(){
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
processTheDatagram(datagram);
}}

QTcpServer::incomingConnection(qintptr) not calling

I'm trying to make client and server using QTcpSocket and QTcpServer.
So, what happens to server.
I run the server, it starts listening (successfully [checked by myself])
I run client, enter 127.0.0.1 for IP address and 30000 for port
Client says that connection estabilished
Server doesn't do anything, just keep waiting
Parts of my program:
//server-work.h
#ifndef SERVERWORK_H
#define SERVERWORK_H
#include <QtCore>
#include <QSqlError>
#include <QDebug>
#include <QSqlQuery>
#include <unistd.h>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtSql/QSqlDatabase>
#include "lssclient.h"
class LSSClient;
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
class LTWorkWithClients : public QThread
{
//Q_OBJECT
public:
LTcpServer* server;
LTWorkWithClients(QObject* parent = 0, LTcpServer *server = 0):
QThread(parent)
{
this->server = server;
}
protected:
void run() {
qDebug() << "started";
server->workWithIncomingConnection();
}
};
QSqlDatabase db; // clients in database
LTWorkWithClients* t_workWithClients;
QQueue<quintptr> clientsToBeAttached;
QList<LSSClient*> clients;
LResult workWithIncomingConnection ();
LResult serverInit ();
LResult createDatabase ();
static QTextStream& qStdout ();
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
protected:
private:
};
#endif // SERVERWORK_H
I know that this nested thread class is strongly wrong way to do this thing, but i don't have much time to do it correctly
// server-work.cpp [PART]
LResult LTcpServer::serverInit()
{
checkError;
db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("serverDB");
if (!db.open()) {
qDebug() << "Error opening database...";
qDebug() << db.lastError().text();
return LVError;
} else {
qDebug() << "Database successfully opened";
}
if(!this->listen(QHostAddress::Any, 30000)){
qDebug() << "Error starting listening...";
return LVError;
} else {
qDebug() << "Start listening successfully";
}
t_workWithClients = new LTWorkWithClients(this, this);
t_workWithClients->start();
return LVSuccess;
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << Q_FUNC_INFO << " new connection";
clientsToBeAttached.enqueue(socketDescriptor);
qDebug() << "here1";
}
LResult LTcpServer::workWithIncomingConnection()
{
bool toExit = false;
while (!toExit) {
checkError;
qDebug() << "1";
if (clientsToBeAttached.length() != 0) {
quintptr eachClientDescriptor = clientsToBeAttached.dequeue();
qDebug() << "2";
LSSClient* client = new LSSClient(this);
client->server = this;
client->socket->setSocketDescriptor(eachClientDescriptor);
qDebug() << "3";
client->registered = false;
client->server = this;
qDebug() << client->socket->localAddress();
connect(client->socket, SIGNAL(readyRead()), client, SLOT(onSokReadyRead()));
connect(client->socket, SIGNAL(connected()), client, SLOT(onSokConnected()));
connect(client->socket, SIGNAL(disconnected()), client, SLOT(onSokDisconnected()));
connect(client->socket, SIGNAL(error(QAbstractSocket::SocketError)),client, SLOT(onSokDisplayError(QAbstractSocket::SocketError)));
clients.append(client);
}
usleep(1000000);
}
return LVSuccess;
}
So, server just keep writing 1 (nothing more) every second, but client says that it is connected to the server.
This structure might help...
in your ltcpserver.h file:
class LTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit LTcpServer(QObject * parent = 0);
void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;
private:
QThread *myThread;
};
and in your ltcpserver.cpp:
LTcpServer::LTcpServer(QObject * parent) : QTcpServer(parent)
{
if(this->listen(QHostAddress::Any,30000))
{
qDebug() << "server started...";
}
else
{
qDebug() << "server could not be started...";
}
myThread = new QThread();
myThread->start();
}
void LTcpServer::incomingConnection(qintptr socketDescriptor)
{
LSSClient * yourClient = new LSSClient(socketDescriptor);
yourClient->moveToThread(myThread);
clients->append(yourClient);
}
and in your lssclient.h
class LSSClient: public QObject
{
Q_OBJECT
public:
explicit LSSClient(qintptr socketDescriptor,QObject * parent = 0);
private:
void setupSocket(qintptr socketDescriptor);
QTcpSocket * socket;
public slots:
void readyRead();
void disconnected();
};
and in your lssclient.cpp
LSSClient::LSSClient(qintptr socketDescriptor,QObject * parent) : QObject(parent)
{
setupSocket(qintptr socketDescriptor);
}
void LSSClient::setupSocket(qintptr socketDescriptor)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(sDescriptor);
connect(socket,SIGNAL(readyRead()),this,SLOT(readyRead()));
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected()));
}
void LSSClient::readyRead()
{
// do whatever you want here with incoming data
}
void LSSClient::disconnected()
{
// do what happens to client when disconnected
}

Qt Threading code different behavior in MAC,Linux and Windows

I have written code for a server which accepts connections from different clients. Each client is serviced in different threads. Each thread accesses a database to get data and then updates this data to all the clients connected to server.
1) For the first time when UI asks data from server, it responds properly, but after that server does not read the socket i.e. Server's readyread() doesn't get invoked. Funnily enough, this works fine in mac and linux, this issue is seen only on windows
2) I was able to verify that when the DB module emits a signal which is caught by the threads, the hang occurs, Because everything worked fine when I removed the emit.
Here, I am attaching all the needed .h and .cpp codes
Defn.h
#ifndef DEFN_H
#define DEFN_H
struct PresetData{
QString ID;
QString name;
QString value;
QString source;
};
#endif // DEFN_H
main.cpp
#include <QCoreApplication>
#include "myserver.h"
#include "mydb.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyDB db;
MyServer server(&db);
server.startServer();
return a.exec();
}
mydb.h
#ifndef MYDB_H
#define MYDB_H
#include <QObject>
#include <QtSql>
#include "Defn.h"
class MyDB : public QObject
{
Q_OBJECT
public:
explicit MyDB(QObject *parent = 0);
signals:
void dataAvailable(QString ID, QString name, QString value, QString source);
public slots:
void onUpdateData(QString ID, QString name, QString value, QString source);
void onGetData(QString ID, QString name, QString value, QString source);
private:
QSqlDatabase m_db;
};
#endif // MYDB_H
mydb.cpp
#include "mydb.h"
MyDB::MyDB(QObject *parent) :
QObject(parent)
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setConnectOptions();
m_db.setDatabaseName("D:/MySimulator/New Folder/TCPServer1/DB.db");
if (m_db.open()){
qDebug() << "DB opened succesfully" ;
}else{
qDebug() << "DB Opening failed" ;
}
QStringList tables = m_db.tables();
if (tables.contains("Presets", Qt::CaseInsensitive)){
qDebug() << "DB Contains Data" ;
return;
}
}
void MyDB::onGetData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onGetData" ;
QString queryString = "SELECT Value from 'Presets' where ID = \'" + ID + "\'";
QSqlQuery q;
bool result = q.exec(queryString);
if (result){
if (q.next()){
value = q.value(q.record().indexOf("Value")).toString();
qDebug() << " Retrieved Value = " << value ;
emit dataAvailable(ID, name, value, source);
}else{
qDebug("Empty Result");
}
}else{
qDebug("NO Result");
}
}
void MyDB::onUpdateData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onUpdateData" ;
QString queryString = "UPDATE 'Presets' SET Value = \'" + value + "'\ WHERE ID = \'" + ID + "\'";
QSqlQuery q;
QSqlDatabase::database().transaction();
bool result = q.exec(queryString);
if (result){
QSqlDatabase::database().commit();
onGetData(ID, name, "", "000");
}else{
qDebug("NO Result");
}
}
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QDebug>
#include "Defn.h"
#include "mydb.h"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int ID, MyDB* db, QObject * parent = 0);
void run();
void parseInput(QString string);
signals:
void error(QTcpSocket::SocketError socketError);
void updateData(QString ID, QString name, QString value, QString source);
void getData(QString ID, QString name, QString value, QString source);
public slots:
void readyRead();
void disconnected();
void onDataAvailable(QString ID, QString name, QString value, QString source);
private:
QTcpSocket* socket;
int socketDescriptor;
MyDB* db;
};
#endif // MYTHREAD_H
mythread.cpp
#include "mythread.h"
#include "qtcpserver.h"
#include "qabstractsocket.h"
MyThread::MyThread(int ID, MyDB* db, QObject * parent ):
QThread(parent)
{
this->socketDescriptor = ID ;
this->db = db;
}
void MyThread::run()
{
// thread starts here.
qDebug() << socketDescriptor << "Starting Thread" ;
socket = new QTcpSocket();
if (!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
connect(this, SIGNAL(getData(QString, QString , QString , QString )), this->db, SLOT(onGetData(QString , QString , QString , QString )));
connect(this, SIGNAL(updateData(QString , QString , QString , QString )), this->db, SLOT(onUpdateData(QString , QString , QString , QString )));
connect(this->db, SIGNAL(dataAvailable(QString , QString , QString , QString )), this, SLOT(onDataAvailable(QString , QString , QString , QString )));
qDebug() << socketDescriptor << "Client Connected" ;
exec();
}
void MyThread::readyRead()
{
QByteArray data = socket->readAll();
qDebug() << socketDescriptor << "Data in: " << data;
parseInput(data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << "Disconnected" ;
socket->deleteLater();
exit(0);
}
void MyThread::parseInput(QString dataFromTCP)
{
qDebug() << socketDescriptor << ":" <<"parseInput " << dataFromTCP;
if (dataFromTCP.isEmpty())
return;
QStringList list1 = dataFromTCP.split("\n", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list1 BEGIN";
for (int i = 0 ; i < list1.count(); i++)
{
qDebug() << i<< ":" << list1.at(i);
}
qDebug() << socketDescriptor << ":" << "list1 END";
if (list1.count() < 1){
return;
}
QString strMessage = "";
for (int i = 0 ; i < list1.count() ; i++)
{
strMessage = list1[i];
QStringList list2 = strMessage.split(" ", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list2 BEGIN";
for (int i = 0 ; i < list2.count(); i++)
{
qDebug() << i<< ":" << list2.at(i);
}
qDebug() << socketDescriptor << ":" << "list2 END";
if (list2.count() < 1){
break;
}
QString ID = list2[1];
QString source = QString::number(socketDescriptor) ;
if (list2[0] == "GET"){
emit getData(ID, "", "", source);
}
else if (list2[0] == "UPD"){
QString value = list2[2];
emit updateData(ID, "", value, source);
}
}
}
void MyThread::onDataAvailable(QString ID, QString name, QString value, QString source)
{
if( (QString::number(socketDescriptor) == source) || ("000" == source ) ) {
qDebug() << socketDescriptor << " : On Data Available " << ID << name << value ;
QString data = "DATA " + ID + " " + value + " " + "\n" ;
QByteArray ba;
ba.append(data);
socket->write(ba);
}
}
myserver.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QDebug>
#include <QObject>
#include <QTCPServer>
#include <QTCPSocket>
#include "mythread.h"
#include "mydb.h"
class MyServer: public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(MyDB* pdb, QObject* parent = 0);
void startServer();
signals:
public slots:
protected:
void incomingConnection(qintptr socketDescriptor);
private:
MyDB* pdb ;
};
#endif // MYSERVER_H
myserver.cpp
#include "myserver.h"
MyServer::MyServer(MyDB* pdb, QObject* parent ):
QTcpServer(parent)
{
this->pdb = pdb;
}
void MyServer::startServer()
{
if (!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not Start Server " << this->errorString();
}
else{
qDebug() << " Server Running... ";
}
}
void MyServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting... ";
MyThread *thread = new MyThread(socketDescriptor, pdb, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
Here the signal about which I mentioned above is dataAvailable from "mydb.cpp". If I comment out that line then server responds to client messages. But if that signal is emitted then after the initial response, the server seems to hang and no longer reacts to incoming messages from the client.
The same code is working perfectly fine in mac and linux. But it is having this problem in Windows only.
Could someone let me know what is it that I am doing wrong that it is failing only in Windows?
Thanks in advance for helping me out.
EDIT:
The objective of this code is that whenever a thread causes an update call to the database, EVERY thread including the one that called the update gets informed about the change. So it is EXPECTED that other thread that runs at that time also receives a signal.
This is what is expected of the server:
Be able to allow TCP connections from multiple clients simultaneously.
If any client requests info, it gets the required data over the TCP connection.
If any client updates info, all clients including the updating client, gets a notifications over the TCP connection.
Well, for starters, your code is completely not thread-safe. You create a single instance of MyDB in your main() function, then call it from threads without protecting its data member. Also, signals get emitted, updating data without any protection. What if two threads happen to be running at the same time?
Secondly, and this is more important: whenever you emit dataAvailable() you call functions in other thread objects in your own thread. This is the code path when data arrives:
MyThread::parseInput() emits
MyThread::getData(), which is connected to
MyDB::onGetData(), which emits
MyDb::dataAvailable, which is connected to (drumroll....)
MyThread::onDataAvailable, which eventually calls
socket->write()
So if data arrives in thread #1, you're going to send data from MyThread object #2, #3, #4, etc from .... thread #1. Depending on the OS, this is bad news. I don't know enough about Windows threads but I do know this code is terminally broken.
If all you want to do is update a database and relay the data you can dispense with the threads and use a sequential program that handles sockets using the regular Qt signals and slots just fine.

Resources