PDA

View Full Version : is QTcpSocket really full duplex?



ctarsoaga
16th January 2015, 17:36
BSD stream sockets are full duplex, meaning two connected parties can both send/receive at the same time.

A QTcpSocket (qt socket implementation) has asynchronous support, non blocking mode, but can only belong to one thread, see qt docs. (http://qt-project.org/doc/qt-4.8/threads-qobject.html)


Event driven objects may only be used in a single thread. Specifically, this applies to the timer mechanism and the network module.

Let's say I want a tx thread and a separate rx thread to use the same socket and send/receive data at the same time.

In my understanding this can be 'done' via qt signals/slots, but the socket thread will never really perform the send() and the receive() simultaneously. It just runs the event loop which will do this in a serial fashion and emit the signals when send/receive is done.

Yes, my rx and tx threads can work concurrently and handle the notifications via qt slots, but the socket itself is never really used in full duplex mode.

Is this correct?

wysota
16th January 2015, 18:08
BSD stream sockets are full duplex, meaning two connected parties can both send/receive at the same time.
Qt used BSD sockets under the hood (on a number of platforms, at least).


Let's say I want a tx thread and a separate rx thread
Why?

anda_skoa
16th January 2015, 18:10
The socket always works in full duplex mode.
If you write data you don't have to wait for it to be written until you can receive again or vice versa.

If your application design requires that two threads interact directly with the socket then you need to either use the low level API or a different abstraction than QTcpSocket.
Its design is more along the lines of splitting proccessing and I/O between threads.

Cheers,
_

ctarsoaga
16th January 2015, 21:53
Qt used BSD sockets under the hood (on a number of platforms, at least).


Why?

let's say I have two machines A and B, which both have large tx queues

when I connect A and B I want to be able to
- send all messages queued inside A to the B system [and receive them in B]
- send all messages queued inside B to the A system [and receive them in A]

I don't want the A system to send the whole queue and wait until that happens, and only later to receive all the messages coming from B.

My question is really if I can send() and receive() at the same time in these A and B systems using QTcpSocket.

From what I know this is not directly possible - since the event loop thread cannot do two calls at the same time.

I'm pretty sure that internally, the socket is a full duplex one so it has this capability.

And I was kind of hoping that the low level implementation is also asynchronous and actually allows read/write at the same time (e.g. the kernel).

wysota
16th January 2015, 22:23
I don't want the A system to send the whole queue and wait until that happens, and only later to receive all the messages coming from B.

My question is really if I can send() and receive() at the same time in these A and B systems using QTcpSocket.
I don't really see what this has to do with threads.


From what I know this is not directly possible - since the event loop thread cannot do two calls at the same time.
The socket "sends" and "receives" outside your application process. So it is just a matter what you read and write to the system buffer. If you have 10 megabytes worth of data to read, nobody forces you to read all that data in one go. And the event loop doesn't have anything to do with that as well as it is your decision when you read or write the data. The loop only notifies you there is something to read.

ctarsoaga
16th January 2015, 22:58
I don't really see what this has to do with threads.


The socket "sends" and "receives" outside your application process. So it is just a matter what you read and write to the system buffer. If you have 10 megabytes worth of data to read, nobody forces you to read all that data in one go. And the event loop doesn't have anything to do with that as well as it is your decision when you read or write the data. The loop only notifies you there is something to read.


I can imagine that a full duplex socket between A and B, internally contains two independent channels
One that can be used to send data from A to B
And another one that can be used to send data from B to A.
On the same socket!
And in 100% parallel fashion!

Let's say I have two cores, two threads running in parallel (no concurrency but true parallelism).

But from what I know I can only use a QTcpSocket from his own thread.

Which means my qt app cannot ever call send() and receive() at the same(!) time on the same(!) socket.
Because this requires separate threads (if parallel).

-----------

Which makes me wonder if I can really exploit the full duplex feature of the underlying socket.

Which I guess is only possible if QTcpSocket's send()/receive() is implemented as non blocking, and the kernel can really let the socket data flow in parallel, in both directions.

thanks a lot for your time
Chris

wysota
17th January 2015, 00:14
I can imagine that a full duplex socket between A and B, internally contains two independent channels
One that can be used to send data from A to B
And another one that can be used to send data from B to A.
On the same socket!
And in 100% parallel fashion!

Let's say I have two cores, two threads running in parallel (no concurrency but true parallelism).

But from what I know I can only use a QTcpSocket from his own thread.

Which means my qt app cannot ever call send() and receive() at the same(!) time on the same(!) socket.
Because this requires separate threads (if parallel).
I think you are missing the point. When you issue a ::write() call, nothing gets written to the socket (surprise, surprise). Similar to that when you call ::read() nothing gets read from the socket (surprise, surprise again). Instead you are writing to and reading from system buffers. And it is your TCP/IP stack which decides when to send data through the socket and when to read data from the socket. So it doesn't matter if you read and write to the socket at the same time or if you switch between reading and writing provided that you do that "often enough". Using non-blocking sockets (such as those offered by Qt) gives you exactly that. Considering that reading and writing to the socket in reality is just copying data between user and kernel space (or just tossing memory pages around) this happens in neglectible time compared to what you do with the data after you read it or before you write it. So you should better focus on that instead.

anda_skoa
17th January 2015, 13:36
I don't want the A system to send the whole queue and wait until that happens, and only later to receive all the messages coming from B.


This is exactly how it works.
Oh wait, I already wrote that.

Cheers,
_

ctarsoaga
17th January 2015, 22:58
Hi everybody,

Thanks you all for your answers.

Yes, indeed, I was missing the point. I am aware of the nonblocking mode being used by the QTcpSocket but I was asking the question as if everything works in blocking mode. I am tired!

You are correct, in nonblocking mode everything is really asynchronous (relative to my read()/write() calls), I don't have to worry at all about this full duplex issue, is under os control anyway.

Thanks a lot for helping me understand this and clarifying the details on how this works.

Chris

wysota
17th January 2015, 23:52
You don't have to worry as long as you let your application process its events. If you, however, block the event loop, your application will not be getting notified of incoming data.