PDA

View Full Version : Background Question about QTcpSocket



sm3.142
26th September 2007, 22:35
Hi,

I wonder if anybody here knows of some background information about how something like the QtTcpSocket class works works with the event loop? The concept I'm trying to wrap my brain around is how to implement something like the readyRead() signal, respectively make sure that it's promptly emitted when there is data available. I've tried to look at the source, but it's a pretty bewildering heap of different classes, definitely not so easy to see through.

I guess the fundamental question could be phrased in even more generic terms: How does the main loop, in a single threaded application, ensure that every class can emit its signals when it decides it needs too? I've looked at a fair number of documents about event-driver programming, but haven't found this particular issue addressed anywhere. The common assumption in introductory texts seems to be that the external events originate in a single place, e.g. from the GUI API, e.g. key press, mouse click etc., and it's the main loop / event handler that collects them.

However, in the context of a concrete Qt example - e.g. QTcpSocket - you just instantiate this object, connect it's signals and more or less forget about it. And when the time comes it emits a readyRead signal sort of on its own. I'd have thought that it might be implemented with a timer inside the QSocket object, but I can't find any use of QTimer in the networking source code for the life of me, at least not pertaining to socket read.

The background is of course that I want to learn how to write my own classes that exhibit this sort of behavior, i.e. waiting for some external resource to become ready (without blocking the event loop) and then emit a signal when it finally does.

I feel right stupid because it seems this should somehow be obvious to me, but I just can't figure it out :confused: Maybe just a little shove in the right direction is needed...

many thanks
-stefan

jacek
26th September 2007, 23:22
Event dispatcher holds a list of all QSocketNotifiers and it simply activates them at the Right Time(tm). Socket notifiers are responsible for checking whether there is any data available using non-blocking I/O and functions like select(2). On the other hand there's also QFileSystemWatcher, which spawns a new thread responsible for monitoring. The third solution, as you already have mentioned, is to use a QTimer to implement polling.

sm3.142
27th September 2007, 13:36
Aha. I think I get it - sort of. Thanks for the hint, jacek. So in summery, these are the three strategies to implement such behaviour:

1) Separate thread with or without its own event loop
2) Qtimer based polling
3) Directly integrating with the event loop like QSocketNotifier does.

I wonder however, if the third strategy is even feasible without customizing the event loop itself. In a nutshell, how would you go about doing that?

jacek
27th September 2007, 14:29
I wonder however, if the third strategy is even feasible without customizing the event loop itself. In a nutshell, how would you go about doing that?
You can use QAbstractEventDispatcher to plug into the event loop. On Unices by default Qt uses Glib event loop, so you can use Glib mechanisms as well.

AaronMK
4th October 2007, 02:11
The Timer based polling scheme sounds a lot more complex than what is needed.

All I really needed to do for a TCP client connection was create a QTcpSocket and connect slots to the signals readyread(), error(), stateChanged(), and bytesWritten() to find out about all events of interest.

The QTcpServer required its own thread, but you can just derive from QThread. Create the server, connect your signals, and call exec() to start message mapping in your run() override.

I remember there few caveats, but having to periodically poll or reaching into the event loop were not among them.

jacek
4th October 2007, 11:49
All I really needed to do for a TCP client connection was create a QTcpSocket and connect slots to the signals readyread(), error(), stateChanged(), and bytesWritten() to find out about all events of interest.
Of course you are right and for simple applications you even don't need a separate thread, but the real question of this thread was "How does the main loop, in a single threaded application, ensure that every class can emit its signals when it decides it needs too?".

sm3.142
4th October 2007, 22:32
I think I understand now how it works in principal. Given the inherent complexity of working with QAbstractEventDispatcher, I've decided to wimp out for now and just go for an operation that blocks with a timeout.

Since the particular thread can't do much anyway if the resource in question is unavailable, blocking the event loop in chunks is no great hardship as long as it's not blocked indefinitely. The main remaining issue is that while the blocking operation is having a go, you can't immediately stop the thread from a controlling thread by calling the formers QThread::stop() slot. However, it will get around to process the signal eventually, when the blocking operation times out. Net effect is that the whole tear down procedure might be delayed a bit, but that's acceptable for my app.

Thanks everybody for responding.
-stefan