Qt new thread are created every tick? - c++

Why every tick of QTimer creates new thread? My application needs to run as long as possible, but after xx of ticks it freeze, it still running (it's responding), but next ticks are not executed. I looked into debug info and i saw:
QThread::start: Failed to create thread () QThread::start: Failed to
create thread () QThread::start: Failed to create thread ()
QThread::start: Failed to create thread () QThread::start: Failed to
create thread () QThread::start: Failed to create thread ()
QThread::start: Failed to create thread () QThread::start: Failed to
create thread ()
waat?
Tick are executed every xx seconds, signal is located into QWidged (which is a one of tab of TabWidget)
namespace Ui {
class accountTab;
}
class accountTab : public QMainWindow
{
Q_OBJECT
public:
explicit accountTab(QWidget *parent = 0);
class player *_player;
~accountTab();
private slots:
void on_clean_timer_clicked();
public:
Ui::accountTab *ui;
};
void accountTab::on_clean_timer_clicked()
{
if(user->timers.value("clean")->isActive()) {
_player->timers.value("clean")->stop();
}
else if(!user->timers.value("clean")->isActive()) {
_player->timers.value("clean")->start(1800000); //900000
}
}
_player is a simple class.
_player->clean() execute a few static classes, which are try/catched.
player.h
class player : public QObject
{
Q_OBJECT
public:
player();
~player();
player(Ui::accountTab *tab, std::string login, std::string password);
player(Ui::accountTab *tab, User user);
public:
bool logIn();
Ui::accountTab *tab = new Ui::accountTab();
public slots:
void clean();
private:
User user;
QMap<std::string, QTimer*> timers;
void initializeTimers();
};
player.cpp
player::player(Ui::accountTab *tab, std::string login, std::string password)
{
this->tab = tab;
this->user.login = login;
this->user.password = password;
}
player::~player()
{
delete this->manager;
delete this->tab;
}
bool player::logIn()
{
...
Log::writeLog("Login completed!", *this);
return true;
}
bool player::setup(bool saved, bool save)
{
if(!this->logIn())
return false;
Packets::sendPacket("getSimulation", *this);
this->initializeTimers();
return true;
}
void player::initializeTimers()
{
this->timers.insert("clean", new QTimer(this));
connect(this->timers.value("clean"), SIGNAL(timeout()), this, SLOT(cleanZoo()));
}
void player::clean()
{
Packets::sendPacket()
}
user class in player class keeps login and password.
timers is a QMap: QMap timers;
Packets::sendPacket() is static void
and sendPacket()
QString httpManager::sendPacket()
{
QNetworkRequest request("https://www.google.pl/");
if(headers.size() > 0) {
for (QMap<const char*, const char*>::iterator i = headers.begin(); i != headers.end(); ++i)
request.setRawHeader(i.key(), i.value());
}
QNetworkAccessManager *manager = new QNetworkAccessManager();
manager->setCookieJar(this->cookies);
QNetworkReply *reply = manager->get(request);
QEventLoop loop;
QObject::connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
loop.exec();
QList<QNetworkCookie> cookies = reply->manager()->cookieJar()->cookiesForUrl(QUrl(reply->url()));
foreach(QNetworkCookie cookie, cookies)
{
this->cookies->insertCookie(cookie);
}
return reply->readAll().data();
}
QEventLoop is executed to get response in the same void. Is this creating new threads?

There are a few things wrong here:
Your application should have a single QNetworkAccessManager that all code uses, don't create one for every call, create one in main and pass that to where it is needed.
You need to delete QNetworkReply using deleteLater as explained in the manual.
Creating another event loop in a function is generally not a good idea. Create a slot on the class httpManager connected to the QNetworkAccessManager::finished(QNetworkReply * reply) signal, read the reply and call deleteLater from here.

Related

Qt Gui Thread is blocking Issue

I'm junior programmer
recently, I have implemented grabbing of Image using Halcon library.
when I press live button, Timer start to grab image. it works but main screen freezes to the timer cycle.
so, I am improving performance grabbing of Image using Thread
first I implemented thread like this
[ImageUpdateWorker.h]
class ImageUpdateWorker : public QObject
{
Q_OBJECT
public:
explicit ImageUpdateWorker(QObject* parent = 0, QString strThreadName = "ImageUpdateWorker");
~ImageUpdateWorker();
signals:
void finished();
void grab();
public slots:
void run();
private:
bool m_bStop{ false };
};
[ImageUpdateWorker.cpp]
ImageUpdateWorker::ImageUpdateWorker(QObject* parent, QString strThreadName)
: QObject(parent)
{
setObjectName(strThreadName);
}
ImageUpdateWorker::~ImageUpdateWorker()
{
}
void ImageUpdateWorker::run()
{
while (m_bStop == false)
{
emit grab();
}
emit finished();
}
second I implemented inherited QWidget UI Widget with output Screen like this
m_pThread = new QThread();
m_pUpdateWorker = new ImageUpdateWorker(nullptr, strName);
m_pUpdateWorker->moveToThread(m_pThread); // UpdateWorker move to Thread
connect(m_pThread, SIGNAL(started()), m_pUpdateWorker, SLOT(run()));
connect(m_pThread, SIGNAL(finished()), m_pThread, SLOT(deleteLater()));
connect(m_pUpdateWorker, SIGNAL(finished()), m_pThread, SLOT(quit()));
connect(m_pUpdateWorker, SIGNAL(finished()), m_pUpdateWorker, SLOT(deleteLater()));
connect(m_pUpdateWorker, SIGNAL(grab()), this, SLOT(onGrab()));
when I call "m_pThread->start();" screen starts to blokcing :(
If you have any advice or information, I would appreciate it. thank you for reading.
Use m_pImageUpdateThread->moveToThread(m_pThread);
I don't know in QT.
I sent you the code I used in C#.
Mainly you must use the delegates if you don't want to freeze the GUI.
hdisplay is the object HalconDotNet:HWindowControlWPF.
camera is a class where I define the camera parameters.
inside camera.Grab there is the code:
HOperatorSet.GrabImage(out ho_Image, _AcqHandle);
h_Image = new HImage(ho_Image);
At the initialization there is the code:
// Initialise the delegate
updateLiveDelegate = new UpdateLiveDelegate(this.UpdateLive);
HImage ho_Image = new HImage();
Here the code I use:
// ==================
// LIVE
// ==================
bool stopLive = true;
// Declare the thread
private Thread liveThread = null;
// Declare a delegate used to communicate with the UI thread
private delegate void UpdateLiveDelegate();
private UpdateLiveDelegate updateLiveDelegate = null;
private void btnLive_Click(object sender, RoutedEventArgs e)
{
try
{
stopLive = !stopLive;
// if stopLive = false, live camera is activated
if (!stopLive)
{
// Launch the thread
liveThread = new Thread(new ThreadStart(Live));
liveThread.Start();
}
}
catch (Exception ex)
{
// Error
}
}
private void Live()
{
try
{
while (stopLive == false)
{
if (camera.Grab(out ho_Image))
{
// Show progress
Dispatcher.Invoke(this.updateLiveDelegate);
}
else
{
// No grab
stopLive = true;
}
}
// here stopLive is true
}
catch (Exception ex)
{
// Error
}
}
private void UpdateLive()
{
try
{
int imageHeight;
int imageWidth;
string imageType;
ho_Image.GetImagePointer1(out imageType, out imageWidth, out imageHeight);
hDisplay.HalconWindow.SetPart(0, 0, imageHeight - 1, imageWidth - 1);
// display
hDisplay.HalconWindow.DispImage(ho_Image);
}
catch (Exception ex)
{
// Error
}
}

How to manage mainwindow from QThread in Qt

My problem is the following one: I have 2 classes (mainwindow and mythread), I run the thread from the mainwindow and I would like to display some QLabel of my mainwindow from mythread :
mythread.cpp :
void mythread::run()
{
while(1)
{
this->read();
}
}
void mythread::read()
{
RF_Power_Control(&MonLecteur, TRUE, 0);
status = ISO14443_3_A_PollCard(&MonLecteur, atq, sak, uid, &uid_len);
if (status != 0){
//display Qlabel in mainwindow
}
}
mainwindow.cpp :
_thread = new mythread();
_thread->start();
You should use Qt's signal/slot mechanism. The thread will emit a signal, that new data has been read. Any interested object can connect to that signal, and perform actions depending on it.
This also works across thread-boundaries, as in your example. In Qt, it is required that only the main-thread interacts with UI elements.
Here is an outline:
// Your mainwindow:
class MyWindow : public QMainWindow {
Q_OBJECT
// as needed
private slots:
void setLabel(const QString &t) { m_label->setText(t); }
};
// Your thread
class MyThread: public QThread {
Q_OBJECT
// as needed
signals:
void statusUpdated(const QString &t);
};
// in your loop
if (status != 0) {
emit statusUpdated("New Status!");
}
// in your mainwindow
_thread = new MyThread;
connect(_thread, &MyThread::statusUpdated, this, &MyWindow::setLabel);
_thread->start();

Getting "destroyed" signal in Qt Script

How to properly connect to QObject's destroyed signal from Qt Script?
When I connect to it like to your average signal, it does not work. I did test that I removed the object and that other QObjects did get the signal, but the script function I connected to it is not invoked.
Below is the sample I'm using for testing. The most important part is the line:
_engine.evaluate("obj.destroyed.connect(function() { debug(\"obj destroyed\") })");
I'd expect it to invoke that function when obj is destroyed. The code below ensures that object is deleted when even loop already started and it also tests that the object did send destroyed signal to another QObject. What I want to fix is for the script to invoke the script function with debug("obj destroyed") after destroyed signal is emitted.
ScriptTester.h:
#ifndef SCRIPTTESTER_H
#define SCRIPTTESTER_H
#include <QtScript>
#include <QtCore>
class ScriptTester: public QObject {
Q_OBJECT
public:
explicit ScriptTester(QObject *parent = 0);
private slots:
void signalTest();
void boo();
private:
QScriptEngine _engine;
};
#endif // SCRIPTTESTER_H
ScriptTester.cpp:
#include "ScriptTester.h"
static QScriptValue scriptDebug(QScriptContext *context, QScriptEngine *engine) {
Q_UNUSED(engine);
if (context->argumentCount() >= 1) {
QString msg = context->argument(0).toString();
for (int i = 1; i < context->argumentCount(); ++i) {
msg = msg.arg(context->argument(i).toString());
}
qDebug() << msg;
}
return QScriptValue();
}
ScriptTester::ScriptTester(QObject *parent) :
QObject(parent)
{
QTimer::singleShot(0, Qt::CoarseTimer, this, SLOT(signalTest()));
_engine.globalObject().setProperty("debug", _engine.newFunction(scriptDebug, 1));
}
void ScriptTester::signalTest() {
QObject *obj = new QObject(this);
_engine.globalObject().setProperty("obj", _engine.newQObject(obj));
_engine.evaluate("obj.destroyed.connect(function() { debug(\"obj destroyed\") })");
if (_engine.hasUncaughtException()) {
qDebug() << "Exception:" << _engine.uncaughtException().toString();
}
connect(obj, SIGNAL(destroyed()), this, SLOT(boo()));
QTimer *timer = new QTimer;
_engine.globalObject().setProperty("timer", _engine.newQObject(timer));
_engine.evaluate("timer.timeout.connect(function() { debug(\"timer timeout\"); obj.deleteLater(); })");
if (_engine.hasUncaughtException()) {
qDebug() << "Exception:" << _engine.uncaughtException().toString();
}
timer->setSingleShot(true);
timer->start(100);
}
void ScriptTester::boo() {
qDebug() << "was destroyed!";
}
Note that I don't want a hack like passing destroyed first to C++ code and then manually or by a signal informing script of that. I'm searching for an implementation that's done fully in the script.

Thread executed only once

I try to implement this: when app is started I need to create multiple threads that would use the same QDialog window to get messages from user. When thread is started, it asks user for input and if button OK pressed, it prints the message to console. I can't figure out why but I get dialog window only once and after that it prints my one message to console and application finishes.
Here's how I describe dialog window:
#include <QtWidgets>
class MyDialog : public QDialog
{
Q_OBJECT
public:
QWaitCondition* condition;
explicit MyDialog(QWidget *parent = 0);
signals:
void got_message(QString);
public slots:
void show_message_input();
void show_message();
private:
QLabel* message_label;
QVBoxLayout* vbox;
QHBoxLayout* hbox;
QLineEdit* message_input;
QDialogButtonBox* dialog_buttons;
};
MyDialog::MyDialog(QWidget *parent) : QDialog(parent)
{
setModal(true);
message_label = new QLabel("Message");
message_input = new QLineEdit();
dialog_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
hbox = new QHBoxLayout();
hbox->addWidget(message_label);
hbox->addWidget(message_input);
vbox = new QVBoxLayout();
vbox->addLayout(hbox);
vbox->addWidget(dialog_buttons);
setLayout(vbox);
connect(dialog_buttons, SIGNAL(accepted()), this, SLOT(accept()));
connect(dialog_buttons, SIGNAL(rejected()), this, SLOT(reject()));
condition = new QWaitCondition();
}
void MyDialog::show_message_input()
{
int result = this->exec();
if (result == QDialog::Accepted)
{
emit got_message(message_input->text());
condition->wakeAll();
}
}
Here's MyThread class:
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int id, MyDialog* window, QObject *parent = 0);
signals:
void show_input();
public slots:
void print_message(QString);
private:
static QMutex mutex;
static QMutex mutex2;
MyDialog* window;
int id;
void run();
void get_captcha_value();
};
QMutex MyThread::mutex;
QMutex MyThread::mutex2;
MyThread::MyThread(int id, MyDialog* window, QObject *parent) :
QThread(parent)
{
this->id = id;
this->window = window;
connect(this, SIGNAL(show_input()), this->window, SLOT(show_message_input()));
}
void MyThread::get_captcha_value()
{
QMutexLocker lock(&mutex);
connect(this->window, SIGNAL(got_message(QString)), SLOT(print_message(QString)));
emit show_input();
mutex2.lock();
window->condition->wait(&mutex2);
mutex2.unlock();
}
void MyThread::run()
{
mutex.lock();
qDebug() << "Starting thread " << id;
mutex.unlock();
get_captcha_value();
mutex.lock();
qDebug() << "Finishing thread " << id;
mutex.unlock();
}
void MyThread::print_message(QString message)
{
qDebug() << message;
QObject::disconnect(this, SLOT(print_message(QString)));
}
And main function:
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyDialog* window = new MyDialog();
QList<MyThread*> threads;
for(int i = 0; i < 5; i++)
{
MyThread* thread = new MyThread(i, window);
threads << thread;
thread->start();
}
return a.exec();
}
The first problem you have is that you're inheriting from QThread. Unless you're wanting to re-write how Qt handles threading, you're doing it wrong!.
What you need to do is have a class that inherits from QObject and move the instances to a new thread. The main problem from inheriting QThread is that it can cause confusion about thread affinity (which thread an object is running on).
Also, creating more threads than processor cores is just a waste of resources.
I suggest you read this article on how to use Qt threading and stop inheriting from QThread.
Finally, the use of QMutex is to protect multiple threads accessing the same data simultaneously. You should be able to remove all of them in the code you've shown. Emitting signals with data from one thread to be received by a slot on another thread is the preferred method in Qt.

Server thread inside a qt class (need mutex?)

I made this server class that starts a thread when new connection comes in. It works ok with some cases, but it's not very stable. I am trying to solve where it breaks. My debugger tells me something about qmutex. If anyone can spot the problem. ty
It connects with parent with signal&slots and gets data back also.
Here is the header:
#ifndef FORTUNESERVER_H
#define FORTUNESERVER_H
#include <QStringList>
#include <QTcpServer>
#include <QThread>
#include <QTcpSocket>
#include <string>
using namespace std;
class FortuneServer : public QTcpServer
{
Q_OBJECT
public:
FortuneServer(QObject *parent = 0);
public slots:
void procesServerString(string serverString);
void getStringToThread(string serverString);
protected:
void incomingConnection(int socketDescriptor);
private:
QStringList fortunes;
signals:
void procesServerStringToParent(string serverString);
void getStringToThreadSignal(string serverString);
};
class FortuneThread : public QObject
{
Q_OBJECT
public:
FortuneThread(int socketDescriptor, QObject *parent);
public slots:
void getString();
void sendString(string sendoutString);
signals:
void error(QTcpSocket::SocketError socketError);
void fromThreadString(string serverString);
void finished();
private:
int socketDescriptor;
QString text;
QTcpSocket tcpSocket;
};
#endif
and cc:
#include <stdlib.h>
#include <QtNetwork>
#include "MeshServer.hh"
#include <iostream>
#include "TableView.hh"
using namespace std;
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::procesServerString(string serverString){
emit procesServerStringToParent(serverString);
}
void FortuneServer::getStringToThread(string serverString){
emit getStringToThreadSignal(serverString);
}
void FortuneServer::incomingConnection(int socketDescriptor)
{
FortuneThread *serverthread = new FortuneThread(socketDescriptor, this);
//connect(&serverthread, SIGNAL(finished()), &serverthread, SLOT(deleteLater()));
QThread* thread = new QThread;
serverthread->moveToThread(thread);
connect(thread, SIGNAL(started()), serverthread, SLOT(getString()));
connect(serverthread, SIGNAL(fromThreadString(string)), this, SLOT(procesServerString(string)));
connect(this, SIGNAL(getStringToThreadSignal(string)), serverthread, SLOT(sendString(string)));
connect(serverthread, SIGNAL(finished()), thread, SLOT(quit()));
connect(serverthread, SIGNAL(finished()), serverthread, SLOT(deleteLater()));
connect(serverthread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
: QObject(parent), socketDescriptor(socketDescriptor)
{
}
void FortuneThread::getString()
{
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
cout<<"socket error"<<endl;
return;
}
//in part
if(!tcpSocket.waitForReadyRead(10000)){
emit finished();
return;
}
int joj = tcpSocket.bytesAvailable();
char inbuffer[1024];
tcpSocket.read(inbuffer,1024);
string instring;
instring = inbuffer;
instring.resize(joj);
emit fromThreadString(instring);
}
void FortuneThread::sendString(string sendoutString)
{
//out part
char buffer[1024];
int buffer_len = 1024;
int bytecount;
memset(buffer, '\0', buffer_len);
string outstring = sendoutString;
int TempNumOne= (int)outstring.size();
for (int a=0;a<TempNumOne;a++)
{
buffer[a]=outstring[a];
}
QByteArray block;
block = buffer;
tcpSocket.write(block);
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
emit finished();
}
this is from parent:
//server start
QHostAddress adr;
adr.setAddress( QString("127.0.0.1") );
adr.toIPv4Address();
quint16 port = 1101;
if (!server.listen( adr, port)) {
QMessageBox::critical(this, tr("CR_bypasser"),
tr("Unable to start the server: %1.")
.arg(server.errorString()));
close();
return;
}
QString ipAddress;
ipAddress = server.serverAddress().toString();
statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
"Run the Fortune Client example now.")
.arg(ipAddress).arg(server.serverPort()));
connect (&server, SIGNAL(procesServerStringToParent(string)), this, SLOT(procesServerString(string)));
connect (this, SIGNAL(StringToServer(string)), &server, SLOT(getStringToThread(string)));
edit: what I am trying to do:
I have a client (part of a game engine(Cryengine)) that I made to send string of ingame coordinates and some other things with a socket like its done in a link I gave before. This works ok. I get data on "127.0.0.1" port 1101. Now I just need this data to be evaluated in my own program, that has this TableView class, inside which I can collect coordinates I get from the string, callculate some data from coordinates and then return this new string back through the server to gameengine. In game I will click on objects get their coor., make a string out of that (containing coor,entityid, etc..), send this string to server, that returns callculated info from TableView. I just need this one way flow only one client that is sending strings. I am not sure about recv(hsock, buffer, buffer_len, 0), I guess node that is responsible for string sending in game will wait for return string? This is one of my first programs atm I am realy confused...
The code you present is exemplary of cargo cult coding: you do various unnecessary things, apparently in hopes of fixing the problem.
The Likely Crasher ...
There are tons of problems with the code, but I think the cause of the crash is this: tcpSocket.write(block) does not send out a zero-terminated string down the wire. The block is zero-terminated, but the assignment to a byte array does not add this zero termination to the size() of QByteArray. The following code prints 1, even though there is a zero terminating byte internally in the contents of the byte array.
QByteArray arr = "a";
qDebug("len=%d", arr.size());
The receiving code expects the zero termination, but never receives it. You then proceed to assign a non-zero-terminated buffer to std::string:
string instring;
instring = inbuffer;
instring.resize(joj);
The subsequent resize is cargo cult: you're trying to fix the problem after std::string & std::string::operator=(const char*) has already read past your buffer, in all likelihood.
Do not take this to mean that fixing just that is the right way to proceed. Not at all. The right way to proceed is to delete the code you wrote and do it right, without a ton of unnecessary incantations that don't help.
... and All The Other Problems
You've fallen into the trap of believing in magic, perpetuated endlessly in various forums.
The threads are not magical objects that you can just apply to any problem out there in hopes that they help. I don't know what makes people think that threads are magical, but the rule of thumb is: If someone tells you "oh, you should try threads", they are most likely wrong. If they tell that in relation to networking, they are pretty much never right, they are unhelpful, and they don't understand your problem at all (neither do you, it seems). More often than not, threads will not help unless you clearly understand your problem. Qt's networking system is asynchronous: it doesn't block the execution of your code, if you don't use the waitxxxx() functions. You shouldn't use them, by the way, so all is good here. No need for a bazillion threads.
So, it is completely unnecessary to start a new thread per each incoming connection. It will decrease the performance of your server -- especially if the server does simple processing because you add the overhead of context switching and thread creation/dismantling to each connection. You want less than 2 threads per each core in your system, so using QThread::idealThreadCount() for the number of threads in the pool would be a good starting point.
You are also depriving yourself of the benefit of threading since you use the networking thread only to receive the data, and you then send out a fromThreadString(string) signal. I presume that signal is sent to your application's main thread. Now that's just silly, because receiving a bunch of bytes from a network socket is downright trivial. Your threads don't do any work, all the work they do is wasted on their creation and removal.
The code below is a simple example of how one might correctly use the Qt APIs to implement a client-server system that distributes work across the physical cores in a round-robin fashion. It should perform quite well. The Fortune client example included in Qt is very unfortunate indeed, because it's precisely the wrong way to go about things.
What one will notice is:
It's not entirely trivial. Qt could be more helpful, but isn't.
Both the clients and the senders are moved into threads from a thread pool.
Disconnected clients are not deleted, but merely returned to a list of clients
kept by the tread pool. They are reused when a client is called for.
QThread is not derived from. QTcpServer is only derived to access the socket handle.
No functions whose name begins with wait() are used. Everything is handled asynchronously.
The ThreadPool keeps a looked-up QMetaMethod for the newConnection(int) slot of the Client. This is faster than using QMetaObject::invokeMethod() as it has to look things up every time.
A timer running in the main thread sets off a signal-slot chain by deleting the first sender. Each senders' deletion triggers the deletion of the next one. Eventually, the last sender sets off the quit() slot in the thread pool. The latter emits the finished() signal when all threads are indeed finished.
#include <QtCore/QCoreApplication>
#include <QtNetwork/QTcpServer>
#include <QtNetwork/QTcpSocket>
#include <QtCore/QQueue>
#include <QtCore/QThread>
#include <QtCore/QTimer>
#include <QtCore/QMetaMethod>
// Processes data on a socket connection
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject* parent = 0) : QObject(parent), socket(new QTcpSocket(this))
{
connect(socket, SIGNAL(readyRead()), SLOT(newData()));
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(newState(QAbstractSocket::SocketState)));
qDebug("Client()");
}
~Client() { qDebug("~Client()"); }
signals:
void done();
public slots:
void newConnection(int descriptor) {
socket->setSocketDescriptor(descriptor);
}
private slots:
void newData() {
QByteArray data = socket->readAll();
if (0) qDebug("got %d bytes", data.size());
if (0) qDebug("got a string %s", data.constData());
// here we can process the data
}
void newState(QAbstractSocket::SocketState state) {
qDebug("client new state %d", state);
if (state == QAbstractSocket::UnconnectedState) { emit done(); }
}
protected:
QTcpSocket* socket;
int descriptor;
};
// Connects to a client and sends data to it
class Sender : public QObject
{
Q_OBJECT
public:
Sender(const QString & address, quint16 port, QObject * parent = 0) :
QObject(parent), socket(new QTcpSocket(this)),
bytesInFlight(0), maxBytesInFlight(65536*8)
{
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(newState(QAbstractSocket::SocketState)));
connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(sentData(qint64)));
socket->connectToHost(address, port);
qDebug("Sender()");
}
~Sender() { qDebug("~Sender()"); }
protected:
// sends enough data to keep a maximum number of bytes in flight
void sendData() {
qint64 n = maxBytesInFlight - bytesInFlight;
if (n <= 0) return;
bytesInFlight += n;
socket->write(QByteArray(n, 44)); // 44 is the answer, after all
}
protected slots:
void sentData(qint64 n) {
bytesInFlight -= n;
Q_ASSERT(bytesInFlight >= 0);
sendData();
}
void newState(QAbstractSocket::SocketState state) {
qDebug("sender new state %d", state);
if (state == QAbstractSocket::ConnectedState) sendData();
}
protected:
QTcpSocket* socket;
qint64 bytesInFlight;
qint64 maxBytesInFlight;
};
// Keeps track of threads and client objects
class ThreadPool : public QTcpServer
{
Q_OBJECT
public:
ThreadPool(QObject* parent = 0) : QTcpServer(parent), nextThread(0) {
for (int i=0; i < QThread::idealThreadCount(); ++i) {
QThread * thread = new QThread(this);
connect(thread, SIGNAL(finished()), SLOT(threadDone()));
thread->start();
threads << thread;
}
const QMetaObject & mo = Client::staticMetaObject;
int idx = mo.indexOfMethod("newConnection(int)");
Q_ASSERT(idx>=0);
method = mo.method(idx);
}
void poolObject(QObject* obj) const {
if (nextThread >= threads.count()) nextThread = 0;
QThread* thread = threads.at(nextThread);
obj->moveToThread(thread);
}
protected:
void incomingConnection(int descriptor) {
Client * client;
if (threads.isEmpty()) return;
if (! clients.isEmpty()) {
client = clients.dequeue();
} else {
client = new Client();
connect(client, SIGNAL(done()), SLOT(clientDone()));
}
poolObject(client);
method.invoke(client, Q_ARG(int, descriptor));
}
signals:
void finished();
public slots:
void quit() {
foreach (QThread * thread, threads) { thread->quit(); }
}
private slots:
void clientDone() {
clients.removeAll(qobject_cast<Client*>(sender()));
}
void threadDone() {
QThread * thread = qobject_cast<QThread*>(sender());
if (threads.removeAll(thread)) delete thread;
if (threads.isEmpty()) emit finished();
}
private:
QList<QThread*> threads;
QQueue<Client*> clients;
QMetaMethod method;
mutable int nextThread;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ThreadPool server;
if (!server.listen(QHostAddress::Any, 1101)) qCritical("cannot establish a listening server");
const int senderCount = 10;
Sender *prevSender = 0, *firstSender = 0;
for (int i = 0; i < senderCount; ++ i) {
Sender * sender = new Sender("localhost", server.serverPort());
server.poolObject(sender);
if (!firstSender) firstSender = sender;
if (prevSender) sender->connect(prevSender, SIGNAL(destroyed()), SLOT(deleteLater()));
prevSender = sender;
}
QTimer::singleShot(3000, firstSender, SLOT(deleteLater())); // run for 3s
server.connect(prevSender, SIGNAL(destroyed()), SLOT(quit()));
qApp->connect(&server, SIGNAL(finished()), SLOT(quit()));
// Deletion chain: timeout deletes first sender, then subsequent senders are deleted,
// finally the last sender tells the thread pool to quit. Finally, the thread pool
// quits the application.
return a.exec();
}
#include "main.moc"
Given your explanation, you game engine starts up and creates a connection to some port on localhost. Your Qt program is supposed to accept that connection on port 1101, receive some strings, process them, then send them back.
The code is modified to accept the connection on a fixed port number. All of the data processing, including sending the response back, has to be done from the newData() slot. You can also pass that data off to a different thread, if your computations are very complex. By complex I mean tens of thousands of operations like additions and multiplications, or thousands of trig operations.
The Sender class is there just as an example. Your game engine does the sending, of course, so you don't need the Sender class.
I got my old "the wrong way to do it" code to work. I guess this part was where the error was:
//removed
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
emit finished();
...
#include <stdlib.h>
#include <QtNetwork>
#include "MeshServer.hh"
#include <iostream>
#include "TableView.hh"
using namespace std;
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::procesServerString(string serverString){
emit procesServerStringToParent(serverString);
}
void FortuneServer::getStringToThread(string serverString){
emit getStringToThreadSignal(serverString);
}
void FortuneServer::incomingConnection(int socketDescriptor)
{
FortuneThread *serverthread = new FortuneThread(socketDescriptor, this);
//connect(&serverthread, SIGNAL(finished()), &serverthread, SLOT(deleteLater()));
QThread* thread = new QThread;
serverthread->moveToThread(thread);
connect(serverthread, SIGNAL(fromThreadString(string)), this, SLOT(procesServerString(string)));
connect(this, SIGNAL(getStringToThreadSignal(string)), serverthread, SLOT(sendString(string)));
connect(serverthread, SIGNAL(finished()), thread, SLOT(quit()));
connect(serverthread, SIGNAL(finished()), serverthread, SLOT(deleteLater()));
connect(serverthread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent): QObject(parent), socketDescriptor(socketDescriptor)
{
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
cout<<"socket error"<<endl;
emit finished();
return;
}
connect(&tcpSocket, SIGNAL(readyRead()), this, SLOT(getString()));
//connect(&tcpSocket, SIGNAL(disconnected()), this, SLOT(ondisconnected()));
}
void FortuneThread::getString()
{
int joj = tcpSocket.bytesAvailable();
if(joj==0){
tcpSocket.disconnectFromHost();
emit finished();
return;
}
char inbuffer[1024];
int buffer_len = 1024;
memset(inbuffer, '\0', buffer_len);
tcpSocket.read(inbuffer,1024);
string instring;
instring = inbuffer;
instring.resize(joj);
emit fromThreadString(instring);
}
void FortuneThread::sendString(string sendoutString)
{
char buffer2[1024];
int buffer_len = 1024;
memset(buffer2, '\0', buffer_len);
strcat(buffer2,sendoutString.c_str());
tcpSocket.write(buffer2,buffer_len);
}
void FortuneThread::ondisconnected()
{
emit finished();
}