PDA

View Full Version : Client-Server App: Clients stop receiving data when one client leaves



SeriousAlexej
15th August 2015, 20:40
Hello, I am developing a client-server app with QTcpSocket and QTcpServer (right now I have to make a simple chat).
I am testing my app in local network, where there is one server and 2 clients, one client connects to localhost (as it runs on the same machine with the server) and another to 192.168.0.1, server listens at port 25600

Clients connect fine, server stores their QTcpSockets in QList and QMap and when info comes from one client, the server sends it to other clients. If changes happen on server, it sends info to all clients.

Data transfer works fine, but when any client leaves the server, the following code is executed:


void Server::Disconnected() // slot, connected to sockets
{
RemoveClient(qobject_cast<QTcpSocket*>(sender()));
}
void Server::RemoveClient(QTcpSocket* client)
{
QString nick = clients[client]; //clients is a QMap<QTcpSocket*, QString>
//at this line client is removed from map and list, but I don't remember the exact code, I'm writing this post from other machine
foreach(QTcpSocket* s, clientsRaw) //clientsRaw is a QList<QTcpSocket*>
{
//here I want to inform all other clients that participant called 'nick' left
WriteMessage(DT_PLAYERLEFT, nick, s); // this method writes number of bytes to be written, data type and the string to the QTcpSocket
//DT_PLAYERLEFT is const quint16 with value of 5
}
}

The nickname is valid, WriteMessage method works fine as it was tested when I transfered data with all clients online.
But after this code, when I have only 1 client connected to server, the data coming TO client is some junk, while data coming FROM client is read fine. The client code which handles incoming data is valid, but the incoming data after another client's leave does'nt even have meaningful data type. What did I do wrong?

ChrisW67
15th August 2015, 21:53
I would be checking very carefully that the QList of sockets contains the same sockets as the keys of the QMap, and that they are correctly maintained in parallel. (I would consider not having two lists in the first place)

Check you do not have a null pointer in either list. Sender() and a cast can result in 0, and your remove code code can create a map entry with that pointer value (QMap::operator[]() will create default entries if the key does not exist).

The "some junk" that is written may be result of logic errors or poor assumptions in the WriteMessage() function. What does it do if nick is empty? We cannot see that code.

anda_skoa
16th August 2015, 08:33
You are currently also writing data to the socket that has just disconnected, because it is still in the list when you iterate over it.

Cheers,
_

SeriousAlexej
16th August 2015, 11:32
I've removed QList and now use QMap::keys() for iterating through QTcpSockets. I checked the value that comes from sender() in debugger, it is not null and QMap does have such key entry. The iteration does not include the socket that have disconnected because before iterating I remove it from the list, checked that twice. The string to be sent is also not empty and valid (otherwise transmission is canceled). The server code appears to be fine, but somehow after client disconnection other QTcpSockets at server stop sending data as expected, only reading works fine.

Here is the WriteMessage method code, just in case:


void AbstractServer::WriteMessage(quint16 dataType, QString& s, QTcpSocket* socket)
{
if(s.isEmpty()) { return; }
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_4_0);
out << dataType;
out << (quint16)0;
out << s;
out.device()->seek((qint64)sizeof(quint16));
out << (quint16)(block.size() - 2*sizeof(quint16));
socket->write(block);
while(socket->flush());
socket->waitForBytesWritten(); //just in case
}

Update: I've solved the problem, the client side did not recognise data type above 4 (silly me >_>). Thanks for help anyway!