PDA

View Full Version : passing socket instances



smalls
22nd January 2006, 23:39
hi all,

have a client server application.
the server starts a thread for each client.
now when a thread received data from its client, it passes the data to the server which in turn checks the data and broadcasts it to all clients using the threads' sockets created in their run() methods.

well, i heard (i think jacek wrote so in the old qt forum) that this shouldn't be done. but why? up to now i didn't experience any crashes that could have been caused by that...

what alternative should i prefer?

if i write a public function like ServerThread::write(QByteArray&) which the server can call, this wouldn't make any difference since this would be processed in the server's thread any way...would it?

i hope the way i expressed it is not too confusing ;-)
thanks for any replies

smalls

Codepoet
22nd January 2006, 23:53
Just to clarify: Do you want to know why it is bad to use a thread per client or why it is bad to pass (unchecked) data from client A to all other clients?

One thread per client is bad because it does not scale well. Image you have at the beginning 4 clients and 4 threads - ok. 16 - ok. 32 - ok. 64 - bad! 128 - worse! 256? still more? Not a good idea.
You should try to figure out what is limiting you bandwidth: Processing power or slow hard disks or something like that. The usual approach is to do multiplexing (use QSocketNotifier). Here you can use one thread for maybe 16-32 clients. Depends on your specific situation.

Why not pass unchecked data from client A to client B? Your client is insecure. It could be any program pretending to be your client. In games this is critical: Imagine player A says he hit player B and B is now dead - even if he was at the other end of the level ;)

smalls
23rd January 2006, 00:27
hi,
i wanted to know why passing the socket instance between threads is bad. this is what i read in the old forum:

"...and remember that you shouldn't pass QTcpSocket instances between threads. This means also that you can't create such object in thread's constructor."

(well, i guess that 16 clients is above the maximum that i can expect. so i will stick with this (easier) approach :)

Codepoet
23rd January 2006, 00:53
ok:
QTcpSocket is derived from QObject. That means you must not access it outside of the owning thread. When you create your QTcpSocket instance the creating thread is the owner and is responsible for the event queue of the socket. If you now pass the socket instance to another thread the following might happen:
You access from this other thread the socket while the owning thread processes an event which requieres calling a member if your socket instance. That results in undefined behavior because QTcpSocket is not thread safe - only reentrant.
You can push the instance between threads using moveToThread, but constantly pushing around is not a good idea.

But I don't understand why you should not create them in the constructor of your thread... You have to ensure that inside your thread you call exec to start the event loop.

If you have only 16 or so clients my solution would be to use one thread for all network related operations and another for the GUI.

jacek
23rd January 2006, 01:00
But I don't understand why you should not create them in the constructor of your thread...
Because the constructor is run in a different thread. The current one doesn't exist yet.

Also remember that QThread shouldn't be the parent of other objects.

smalls
23rd January 2006, 14:15
so if i decide to do all network related jobs in one thread and the GUI stuff in another
do i have to manage the sockets with the signal/slot mechanism?

right now this server is just for a chat program. but once this is "completed" i would like to modify the server to a game server which would have to be as fast as possible (the game is supposed to be real-time).

is the signal slot mechanism fast enough for this (under windows, linux) ?

Codepoet
23rd January 2006, 17:05
@jacek: thx - when really thinking about it' it's obvious...

Yes, you could do that. In your server first start your network thread. In run you then create your QTcpServer and connect newConnection to your slot (the target instance has to be owned by the network thread). In that slot create your client sockets and QSocketNotifier for them. So everything is managed by signals and slots. Since you are thread local it should be more than fast enough (maybe a little slower than a virtual function call).

If you need realtime it depends much more on your network protocol: TCP is "slower" but reliable (and "easy") UDP is "faster" and unreliable. For the beginning prefer TCP.

wysota
23rd January 2006, 19:17
It is also worth noting, that one can move a QObject between threads, so theoretically it is possible to create a socket in the constructor of the thread and then move it to a thread which will use it.

The whole issue came out when I was implementing a webserver using Qt and threads and had trouble finding the cause of Qt denying to cooperate with my socket. Moving the socket to another thread didn't help, because the thread was still the parent. I think this is a little bit wrong. Creating the socket in the "run()" method (without a parent) helped.

smalls
24th January 2006, 22:32
well,
i read the docu to find out how to implement the server with one network-thread for all clients...

1) start a thread and in it's run() method start the QTcpServer
2) create socket instances in the incomingConnection() slot
3) connect the socket's readyRead()-signal with an apropriate read()-slot
4) store the sockets (e.g. using a vector)

BUT once my read() slot was invoked, how do i tell which of the sockets fired the readyRead() signal???
My idea was to subclass QTcpSocket and add a read() slot in the new class, then connect the sockets readyRead()-signal with its own read() slot. but i don't know if this would work and even if it would i bet this isn't the way it is supposed to be done.

so i would be glad about any comments on that

(BTW: what is QSocketNotifier good for? The docu says:
"Although the class is called QSocketNotifier, it is normally used for other types of devices than sockets. QTcpSocket and QUdpSocket provide notification through signals, so there is normally no need to use a QSocketNotifier on them.")

wysota
24th January 2006, 23:30
Nobody says you should have one thread for all the clients, but that you should have a limited number of threads. You can queue threads and requests, and if there are more requests than threads, some of them will have to wait a little.

Codepoet
24th January 2006, 23:36
You can use QObject::sender() to get the socket - just cast it to the right class - or use a QSignalMapper.


QSocketNotifier:
this->RTFM() :rolleyes:
From my former knowledge of several network APIs and the existence of that class it was so obvious to me what one should do with it... The real problem is probably that I'm not beyond planning stage of the network part of my project.