[SOLVED]Nonblocking/blocking singlethreaded QTcpserver with multiple simultaneous QTcpSockets
-
I have to implement a server which can maintain multiple tcpsockets open and receive messages from them. The tcpsockets should all run in the same thread.
Here is the current implementation:
@//server.h
class MyServer : public QTcpServer//server.cpp
void MyServer::on_newConnection(){
QTcpSocket *clientConnection = nextPendingConnection();
if (clientConnection->waitForReadyRead()){
//DO STUFF WITH RECEIVED MESSAGE
}@This implementation uses the blocking "waitForReadyRead()":http://qt-project.org/doc/qt-5.0/qtnetwork/qabstractsocket.html#waitForReadyRead with the default value. Meaning it waits for 30 seconds for the message to become available.
But the wiki "Threads, Events and QObjects":http://qt-project.org/wiki/Threads_Events_QObjects states:
bq. Networking: all low-level Qt networking classes (QTcpSocket, QUdpSocket, QTcpServer, etc.) are asynchronous by design. When you call read(), they just return already available data; when you call write(), they schedule the writing for later. It’s only when you return to the event loop the actual reading/writing takes place. Notice that they do offer synchronous methods (the waitFor* family of methods), but their use is discouraged because they block the event loop while waiting. High-level classes, like QNetworkAccessManager, simply do not offer any synchronous API and require an event loop.
Please help me to understand the following:
-
What happens in the current implementation in the following situation. Client1 is connected to the Server. The Server is blocked in waitForReadyRead() waiting for Client1 to send the message. At that same time Client 2 tries to establish a connection with the Server.
Is the socket identifier for Client2 placed on some queue and will be returned next time the Server calls nextPendingConnection() even dough the server is currently blocked with waitForReadyRead() ? -
How to implement this without the blocking call?
-
-
just connect a slot to the "readyRead()":http://qt-project.org/doc/qt-4.8/qiodevice.html#readyRead signal.
If possible always try to avoid blocking calls in an event-driven framework. -
QTcpSocket is QIODevice which has readyRead() signal to inform there is data waiting.
So connect that signal to slot etc where you handle it.
For example with Qt5 and C++11:
@
void MyServer::on_newConnection(){
QTcpSocket *clientConnection = nextPendingConnection();
QObject::connect(clientConnection, &QTcpSocket::readyRead, clientConnection{
QByteArray data = clientConnection->readAll();
// handle data
}
@ -
Thank you for your answers.
It didn't occur to me to define the SLOT implementation in the connect. :) -
Something came up when i did the change.
The // handle data part needs a way to modify the server. And that isn't working with the event loop approach.
Here is a conceptual pseudo code which works in the case with the blocking call.
@ //server.h
class MyServer : public QTcpServer
QList<Client> listOfClients;//server.cpp void MyServer::on_newConnection(){ QTcpSocket *clientConnection = nextPendingConnection(); if (clientConnection->waitForReadyRead()){ // Populate the list of clients based on received data listOfClients.append(received_data) }@
In the non blocking i have to somehow pass the pointer to the MyServer object. Is there a clean way of doing this?
-
Figured it out.
The solution is knowing "what a lambda function is":http://www.cprogramming.com/c++11/c++11-lambda-closures.html and how to pass the local scope to them.
However, it seems the new syntax for "connect":http://qt-project.org/wiki/New_Signal_Slot_Syntax isn't being recognized.
@QObject::connect(clientConnection, &QTcpSocket::readyRead, &{
QByteArray data = clientConnection->readAll();
//DO STUFF
});@Results in a
bq. error: no matching function for call to 'MyServer::connect(QTcpSocket*&, void (QIODevice::*)(), MyServer::on_newConnection()::<lambda()>)'
I bit stuck now. I'm using the Qt 5.1.1 with GCC 4.6.1. will give it a try on other compilers to see if that's the cause.
-
The problem is with the compiler. It runs fine with Qt 5.1.1 (MSVC 2010, 32 bit). That's a different issue. SOLVED