views:

108

answers:

2

I'd like to make a TCP client that makes multiple connections while a select() loop that receives data from them is running in a separate thread. I'm not sure this is possible, though, because the select() loop is already running and thus I don't see how it would "notice" a new socket was added even if the thread-safety issues are dealt with.

Is there a way to do this, or must I spawn a new thread and use recv() every time I make a new connection?

(Edited for clarity.)

+2  A: 

Of course it is possible. The select() function accepts file handles in three sets, one for read, one for write and one for errors. Just add your socket to the read set, and you'll be noticed when the server has sent you something.

This page has code showing how this is done.

unwind
Ok thanks, so even though select() is running in a loop and a socket is added from a totally different thread, where connect() is used, it will still notice that the read set just received a new addition and will begin receiving data on it? It's a bit counterintuitive but I'll try it out.
oskar
Huh? Threads? I thought you said "single thread" in the question. Please edit your question to more clearly describe how you use threads. The FD_SET is (very probably) not thread-safe, so you need to take care if adding sockets to a shared set from many threads.
unwind
Sorry, I assumed that was clear because select() has to run in a loop, thus unless I make all my connections before getting into the loop I'm sort of forced to make my connections in a separate thread.
oskar
By "single thread" I meant that I want to receive all my _data_ from all my current connections in a single thread, but I still need a separate thread to establish those connections. I've edited the question for clarity.
oskar
Would it be safe to assume this is impossible? I could always just make a new thread for each socket and use recv(), but I plan to make a lot of connections during the course of the program so it may turn out to be a lot of threads.
oskar
@oskar: I see ... I don't think it's impossible (few things are, after all :), but it might be complicated. You would need some sort of "incoming connection queue" in which the threads that accept the connections can place the new sockets. The main thread then, before each call to select(), needs to go through and clear the queue, adding all new socket(s) to the FD_SET. Something like that.
unwind
If you call `connect()` on a non-blocking socket the call returns immediately and `select()` returns the socket as "writable" when the connection is established. So you could open the connections in the "receiving" thread.
sth
A: 

Another good reason to select() on client sockets is to track outgoing TCP connections progress. This allows, for example, to setup connection timeout.

  • Set client socket to be non-blocking.
  • Call connect(). Probably it would return with EINPROGRESS error set (connection is in progress, you are not blocked because socket is non-blocking).
  • Now select() with FD_SET configured to track client-socket as 'write-ready'. Also you can set timeout.
  • Analyze select() result.
  • Analyze if last client socket operation was failed or succeed.

The most useful thing is you can use this on several sockets in different state. So you get truly non-blocking handling of number of sockets (client, server, outgoing, listening, accepted ...). And all of this with only one thread.

Roman Nikitchenko