Tag Archives: QTcpServer

Handling / identifying multiple clients with QTcpServer

There are various examples of client-server applications in the Qt documentation, some of them being able to handle more than one client. While is convenient to have an event signalled each time something happens on one of our connected client-sockets, sometimes processing takes more than just answering back. Sometimes we need to be able to connect our socket on which the event occurs,with some other informations related to that client, and the processing could imply informations being sent from / for other clients too.
Regarding this, however seems like none of examples is showing how to identify for what client the data is coming, or more exactly how to make an association between the socket the server is receiving data on, and the corresponding client related data.

I have run couple of tests about what happens in various situations when client connects,disconnects,etc and found out the following:

  • when a new connection is made to server, QTcpServer will emit a newConnection() signal, and then, for the connected client we can get back a QTcpSocket instance, using nextPendingConnection().
  • the QTcpSocket contains the socket descriptor used for communication.
  • hen there is data to be read or data was written to socket, QTcpServer emits signals related to this, and the sender of the signal is a QTcpSocket instance. One could get it by converting the sender() to QTcpSocket*. For a given client, the instance of QTcpSocket will be every time the same.
  • if previous client disconnected and a new client connects, although it is possible to have the same socket descriptor used for communication, the instance of QTcpSocket returned by nextPendingConnection(), and subsequently used in signalling events, will be different one.

Because for each client gets a different and very own QTcpSocket instance, and has this instance while disconnects, one simple approach would be to use this QTcpSocket instance to identiy for what client the event is happening.

But how can we do this?

First, let’s assume we have a Server class, which has a QTcpServer member variable with it’s signals (newConnection()) connected to a slot in Server.
Also, let’s assume our client-related information is stored in a class Client.
For identifying on which Client we get data/data was sent/ error occurred, we simply use a simple QMap stored as a member variable, which maps QTcpSocket* to our Client instance.

QMap<QTcpSocket*, Client*> mClients;

When a new connection arrives on our QTcpServer, the Server slot we set up gets called. Here we retrieve the QTcpSocket, create our Client instance, connect some signals, and store it in our map for later identification:

// connected to mTcpServer::onNewConnection()
// gets called each time a new connection arrives on server
void Server::NewConnection()
{
   QTcpSocket* connection = mServerNextPendingConnection();

   if(connection)
   {
       Client* client = new Client();

       // connect signals to handler slots

       // we assume Server has a slot Error(QAbstractSocket::SocketError))
       connect(connection, SIGNAL(error(QAbstractSocket::SocketError)),
          this, SLOT(error(QAbstractSocket::SocketError));

       // we assume Server has a slot readyRead()
       connect(connection, SIGNAL(readyRead()), this, SLOT(readyRead()));

       //we assume Server has a slot disconnected()
       connect(connection, SIGNAL(disconnected()), this, SLOT(disconnected()));

       //store the TcpSocket,client pair in map
       mClients[connection] = client;
   }
}

When data arrives on socket, the TcpSocket for the given connection will notify server by calling the slot we set up in the incoming connection. Bellow is how you can retrieve on which client this happened:

// gets called when data is available on one of our client QTcpSockets
void Server::readyRead()
{
    // retrieve our sender QTcpSocket
    QTcpSocket* connection = qobject_cast(sender());

    // get our Client
    Client* c = mClients[connection];

    // ...
    // do the processing you have to do with the data comming for this
    // client
    // ...
}

We can retrieve the Client on same way for errors, or when gets disconnected, as these also get their own signal, and the sender for the signal will be the associated QTcpSocket.

As a side note, when disconnected() slot is called, the returned QTcpSocket instance, although it is the same one for a given client as the one used in read and write, will have the underlying socket descriptor set to -1. This means that although we could use socket descriptor as a key in our client map when event such as there is data to be read or data was written to identify the client, on disconnect we cannot figure out for what client we need to free it’s data and resources.