QTcpServer with QThreadPool, for long term connections.
-
Hello,
Was wondering if anyone could point me in the right direction...
Working with sockets and trying to make a multi-threaded TCP server. Anyone that has done this for a large traffic application knows that one thread per-socket is a BAD idea, too many connections and the application crashes.
So I was looking at QThreadPool and QRunnable, but I cannot for the life of me find an example where the socket is a long term connection, or maybe I am just miss-understanding QRunnable.
General concept:
Client connects, the server kicks off a new QRunnable, and the run() function is called.
@void MyRunnable::run()
{ //thread starts heresocket = 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);
...//somehow keep the socket alive even though the QRunnable is done
...//for a thread we would put exec(); here
}void MyRunnable::readyRead()
{
//read data from the socket and send a response
}void MyRunnable:: disconnected ()
{
//make sure the socket is deleted
}@My main problem (or rather concern) is that QRunnable is not the same as a thread, but rather seemed to be a fire and forget kind of class...
Perhaps I am looking at this wrong?
Perhaps all the signal and slots should take place on one thread, and all the socket IO should be called as a QRunnable, in other words, connect all the signals and slots on the main thread, and then each time you want to read or write to and from the socket you make a new QRunnable sub-class for that.
Anyways I come from the C# / VB.Net world and have read a lot about IO completion ports:
http://en.wikipedia.org/wiki/Input/output_completion_portCan anyone point me in the right direction or tell me if I am just generally confused :)
-
You can't use QRunnable here because you need an event loop running.
Moreover, you can't pass QTcpSockets around between threads. They can only be used from the thread they're created. You have to subclass QTcpServer and pass the descriptor to the thread you want to handle the socket, and create the QTcpSocket there. You do this by overriding QTcpServer::incomingConnection.So:
- create your own thread pool of N threads (i.e. N QThreads)
- create N worker objects, one per thread, and move each one into a different thread of the pool
- start the event loops in those threads (i.e. QThread::start on each one)
- in the "main" thread create the server, put it into listening and start the event loop
- when a new connection is received, incomingConnection is called: take the fd and dispatch it to a worker object (using any policy you like)
- the worker object receives the descriptor and creates the QTcpSocket object and calls setSocketDescriptor on it, set up the signal/slot connections etc.
The "passing descriptor" mechanism itself is quite interesting because it can be easily implemented through a custom event containing the descriptor. You just need to create the event and post it to the right worker object. Qt will provide the thread-safe queue.
-
[quote author="peppe" date="1302915836"]You can't use QRunnable here because you need an event loop running. Moreover, you can't pass QTcpSockets around between threads. They can only be used from the thread they're created. You have to subclass QTcpServer and pass the descriptor to the thread you want to handle the socket, and create the QTcpSocket there. You do this by overriding QTcpServer::incomingConnection. So: * create your own thread pool of N threads (i.e. N QThreads) * create N worker objects, one per thread, and move each one into a different thread of the pool * start the event loops in those threads (i.e. QThread::start on each one) * in the "main" thread create the server, put it into listening and start the event loop * when a new connection is received, incomingConnection is called: take the fd and dispatch it to a worker object (using any policy you like) * the worker object receives the descriptor and creates the QTcpSocket object and calls setSocketDescriptor on it, set up the signal/slot connections etc. The "passing descriptor" mechanism itself is quite interesting because it can be easily implemented through a custom event containing the descriptor. You just need to create the event and post it to the right worker object. Qt will provide the thread-safe queue.[/quote]
Thanks, I will give it a shot!
Know of any examples out on the net?
-
I also would like to see some example of this, please.