PDA

View Full Version : QTcpSocket does not send data immediately



igorosberg
13th July 2011, 00:56
Hello everyone,

could someone tell me the reason for the code below does not send the data? I think that the data is being buffered, rather than sent



QByteArray data;

int type_msg = 6;
data.append( (char*)&type_msg, sizeof(int) );

string video_server_address;
in >> video_server_address;

int num_char_video_server_address = video_server_address.size();
data.append( (char*)&num_char_video_server_address, sizeof(int) );

data.append( QString(video_server_address.c_str()) );

int num_bytes_write = clientSocket->write( data.data(), data.size() );
clientSocket->flush();

while( clientSocket->bytesToWrite() > 0 ){
num_bytes_write += clientSocket->write( data.data()+num_bytes_write, data.size()-num_bytes_write );
clientSocket->flush();
clientSocket->waitForBytesWritten();
}



before this code a lot of data has been sent successfully the same way, but these last 17 bytes were not received by the client

clientSocket is a variable whose type is QTcpSocket.

Thanks

Santosh Reddy
13th July 2011, 03:44
I guess you should be checking at the receiving end, the data may not be sent in single packet, make sure that that the receiving end socket is read until no data is left

ChrisW67
13th July 2011, 06:01
There's no such beast as an unbuffered TCP socket, a point made by the QTcpSocket docs:

Note: TCP sockets cannot be opened in QIODevice::Unbuffered mode. You queue stuff to send and the TCP/IP stack looks after sending it, pipeline optimisation, acknowledgement, sequencing, and integrity. It gets there when it gets there... and you can be sure it will.

igorosberg
13th July 2011, 18:30
I guess you should be checking at the receiving end, the data may not be sent in single packet, make sure that that the receiving end socket is read until no data is left

the problem is that the shown code do not emit the readyRead() signal on client side, because of this i can conclude that the data was not sent

Thanks by replies

squidge
13th July 2011, 19:12
Show more of your code, maybe something is happening before the data is actually sent (such as closing the socket or invalidating the socket)

You can only guarantee with waitForBytesWritten that Qt transfers the data to OS buffers. There is no guarantee that the OS has made any attempts to transfer the data at that point.

igorosberg
13th July 2011, 19:43
Show more of your code, maybe something is happening before the data is actually sent (such as closing the socket or invalidating the socket)

You can only guarantee with waitForBytesWritten that Qt transfers the data to OS buffers. There is no guarantee that the OS has made any attempts to transfer the data at that point.

I thought the reason for the server does not send the data is due to the size of the package, that is, the package is very small, then the OS prefers buffered and wait for more data to send everything.

to confirm this fact, after the code shown, I sent another package with size 473 356 bytes and then the first packet arrived at the client, followed by the larger package.

So my belief that this data was buffered instead sent was confirmed.

Could someone tell me how to avoid this type of buffering for small packages? I thought the function flush() had just this goal.

squidge
13th July 2011, 21:53
Your small package will be sent, eventually. It depends on the QOS on the host. Typically it will be less than a second however.

igorosberg
13th July 2011, 23:06
My server handle many connections using multiple threads. i create the threads using the code



HandlerConnection *thread = new HandlerConnection( socketDescriptor, &user_list, this );
connect( thread, SIGNAL(finished()), thread, SLOT(deleteLater()) );
thread->start();


on the constructor method of class HandleConnection there is the follow code



clientSocket = new QTcpSocket();

if(!clientSocket->setSocketDescriptor(socketDescriptor)){
emit error( clientSocket->error() );
return;
}

connect(clientSocket, SIGNAL(readyRead()), this, SLOT(receiveData()), Qt::DirectConnection );

forever{
QCoreApplication::processEvents(QEventLoop::WaitFo rMoreEvents);
}
exec();



after that, the server receive and send data. however, that code in the first post does not work.

Thanks. Waiting for more replies.

squidge
13th July 2011, 23:35
So, your are creating a QTcpSocket in one thread and then expecting to read from it in another thread. That is not going to be reliable.

In fact, if you have "exec" in your constructor, I'm surprised it even returns :confused:

You don't even need threads for multiple connections. All connections can be handled in the main thread.

igorosberg
14th July 2011, 00:24
So, your are creating a QTcpSocket in one thread and then expecting to read from it in another thread. That is not going to be reliable.

I think it is safe, because the example Threaded Fortune Server* (http://doc.trolltech.org/4.7/network-threadedfortuneserver-fortuneserver-cpp.html) creates threads in the same way.


You don't even need threads for multiple connections. All connections can be handled in the main thread.

can all connections be handled in the main thread, at the same time, without block the server? how?

Thanks.

Added after 6 minutes:

the function call exec () can be removed without loss of functionality

squidge
14th July 2011, 08:40
Sockets are, by default, non blocking. You can use QSignalMapper to manage multiple sockets with a single method.

The only time you really need threads is if you want to do intensive cpu operations.

igorosberg
15th July 2011, 16:51
Sockets are, by default, non blocking. You can use QSignalMapper to manage multiple sockets with a single method.

I really did not need the threads so I removed them.

to solve the problem of sending smaller package, I started to send it before sending larger packets. so all reached their destination.

however, this was just a ploy to solve the problem. Still do not see why the last and smallest package does not arrive, when sent last.

Thanks by replies.