PDA

View Full Version : QTcpSocket get disconnected when server is sending huge data



KernelCoder
31st March 2011, 19:43
Before describing my problem, let me first give you the background of my application. There is a tcp server (which is written in Delpi) and a tcp client which I am writing in C++ (Qt). When the client connects to the server, the server sends a large chunk of configuration data to the client (about 3 MB). The problem I am having is that the TCP connection is being disconnected during the receive of this large chunk of data.

I've tried (temporarily) reducing the data size down to a few hundred Kbytes, and sometimes it works, sometimes it fails. It seems to fail more regularly with slower PCs. If I reduce it to 10KB, it works 100% of the time, but I need to be able to have it work with the 3MB of data the host will normally send. I have also experimented with having the host wait for a minute before sending the large chunk of data, and send little chunks first. The smaller chunks (a few KB) work fine, but the disconnect still happens when the large chunk comes in. Also, the number of bytes received before the connection is broken seems to vary randomly.

The server is (currently) running on the same machine, and we are using the loopback address (127.0.0.1) as the connection IP address.

The following is the slot which signaled when data is received:



void Socket::dataReadyToRead()
{
/*
* Let us lock this slot so that further hitting on this cause wait while it is
* already hitted.
*/
QMutexLocker locker(&mMutex);

/*
* We will only read data when at least one command is arrived. Here is the logic...
* We will continue till the length of the next command is arrived. If only length is
* arrived (not content yet), just read it in d->mnBlockSize (NOTE: LSB come first, i.e, little endian),
* leave this method. But if content arrived too, let us read it and process this command.
*/
while(bytesAvailable() >= (int)sizeof(quint32)){
if (0 == mnBlockSize){
/*
* Read the length bytes first. And as LSB come first, need to calc length like following.
*/
char length_byte[4];
read(length_byte,4);

mnBlockSize = length_byte[0];
mnBlockSize += (length_byte[1] * 256);
mnBlockSize += (length_byte[2] * 256 * 256);
mnBlockSize += (length_byte[3] * 256 * 256 * 256);
}

/*
* Content is not available yet, so there is nothing to do.
*/
if (bytesAvailable() < mnBlockSize){
return;
}

/*
* Content arrived, so get it, copy it to a buffer, analyze the packet by calling
* prepareCommand and them emit the prepared packet to the system so that
* contorller get it and process it.
*/
char dataArrived[MAX_DATA_LENGTH];
read(dataArrived,mnBlockSize);

if(mnBlockSize <= MAX_DATA_LENGTH){
QByteArray com(dataArrived,mnBlockSize);
emit commandCame(com);
}

mnBlockSize = 0;
}
}


Following is the thread run method’s code.


void SocketThread::run()
{
if(mTcpHandler){
Socket tcpClient;
connect(mTcpHandler, SIGNAL(connectToBobHost(QString, int)), &tcpClient, SLOT(connectToBobHost(QString, int)));
connect(mTcpHandler, SIGNAL(disconnectFromBobHost()), &tcpClient, SLOT(disconnectFromBobHost()), Qt::BlockingQueuedConnection);
connect(mTcpHandler, SIGNAL(dataReadyToSend(QByteArray)), &tcpClient, SLOT(sendData(QByteArray)));

connect(&tcpClient, SIGNAL(hostConnected()), mTcpHandler, SLOT(hostConnected()));
connect(&tcpClient, SIGNAL(hostDisconnected(bool )), mTcpHandler, SLOT(hostDisconnected(bool)), Qt::BlockingQueuedConnection);
connect(&tcpClient, SIGNAL(hostNotConnected(const QString&)), mTcpHandler, SLOT(hostNotConnected(const QString&)));
connect(&tcpClient, SIGNAL(commandCame(QByteArray)), mTcpHandler, SLOT(analyzeCommand(QByteArray)));
exec();
}
}


Can anyone help please?

wysota
31st March 2011, 20:31
First of all you don't need the mutex. Second of all who is breaking the connection - the server or the client? Third of all make sure you get correct values for the block size on the client, your way of assembling it is quite strange, usually one uses bit shifting for it or qFromLittleEndian().

KernelCoder
1st April 2011, 06:11
Thank you very much wysota for replying.

- Yes, I tried even without mutex-ing.

- I see in the client side that, the disconnnected signal of Socket is being invoked and the error at that time was 'RemoteHostClosedError'.


void Socket::onHostDisconnected()
{
emit hostDisconnected(error() != QAbstractSocket::UnknownSocketError);
}

I saw that the code returns by 'error()' is 'RemoteHostClosedError'. Note that this is my problem.

- Yes, qFromLittleEndian works for me too (thank you), but mine one is ok too.

mcosta
1st April 2011, 08:45
QAbstractSocket::RemoteHostClosedError means that the server closed the socket while you're receiving data.

I suggest you to use a LanSniffer (Wireshark) to see what the server does when it send you data.