Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Besides the fact you want to go from single-client to multi-client, it's not very clear what's blocking you here.</p> <p>Are you sure you fully understood how does <code>select</code> is supposed to work ? The manual (<code>man 2 select</code> on Linux) may be helpful, as it provides a simple example. You can also check <a href="http://en.wikipedia.org/wiki/Select_%28Unix%29" rel="nofollow">Wikipedia</a>. </p> <p>To answer your questions :</p> <ol> <li><p>First of all, are you <em>sure</em> you need non-blocking mode for your sockets ? Unless you have a good reason to do so, blocking sockets are also fine for multi-client networking.</p></li> <li><p>Usually, there are basically two ways to deal with multi-clients in C: <code>fork</code>, or <code>select</code>. The two aren't really used altogether (or I don't know how :-) ). Models using lightweight threads are essentially <a href="http://en.wikipedia.org/wiki/Asynchronous_programming" rel="nofollow">asynchronous programming</a> (did I mention it also depends on what you mean by 'asynchronous' ?) and may be a bit overkill for what you seem to do (a good example in C++ is <a href="http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio.html" rel="nofollow">Boost.Asio</a>).</p></li> </ol> <p>As you probably already know, the main problem when dealing with more than one client is that I/O operations, like a <code>read</code>, are blocking, not letting us know when there's a new client, or when a client has said something.</p> <p>The <code>fork</code> way is pretty straighforward : the server socket (the one which accepts the connections) is in the main process, and each time it accepts a new client, it forks a whole new process just to monitor this new client : this new process will be dedicated to it. Since there's one process per client, we don't care if i/o operations are blocking or not.</p> <p>The <code>select</code> way allows us to monitor multiple clients in one same process : it is a multiplexer telling us when something happens on the sockets we give it. The base idea, on the server side, is first to put the server socket on the read_fds FD_SET of the select. Each time <code>select</code> returns, you need to do a special check for it : if the server socket is set in the read_fds set (using FD_ISSET(...)), it means you have a new client connecting : you can then call <code>accept</code> on your server socket to create the connection. Then you have to put all your clients sockets in the fd_sets you give to <code>select</code> in order to monitor any change on it (e.g., incoming messages).</p> <p>I'm not really sure of what you don't understand about <code>select</code>, so that's for the big explaination. But long story short, <code>select</code> is a clean and neat way to do single-threaded, synchronous networking, and it can absolutely manage multiple clients at the same time without using any <code>fork</code> or threads. Be aware though that if you absolutely want to deal with non-blocking sockets with <code>select</code>, you have to deal extra error conditions that wouldn't be in a blocking way (the Wikipedia example shows it well as they have to check if <code>errno</code> isn't <code>EWOULDBLOCK</code>). But that's another story.</p> <p><strong>EDIT</strong> : Okay, with a little more code it's easier to know what's wrong.</p> <ol> <li><code>select</code>'s first parameter should be nfds+1, i.e. "the highest-numbered file descriptor in any of the three sets, plus 1" (cf. manual), not FD_SETSIZE, which is the maximum size of an FD_SET. Usually it is the last <code>accept</code>-ed client socket (or the server socket at beginning) who has it.</li> <li><ol> <li>You shouldn't do the "CHECK all file descriptors" for loop like that. FD_SETSIZE, e.g. on my machine, equal to 1024. That means once select returns, even if you have just one client you would be passing in the loop 1024 times ! You can set <code>fd</code> to 0 (like in the Wikipedia example), but since 0 is <code>stdin</code>, 1 <code>stdout</code> and 2 <code>stderr</code>, unless you're monitoring one of those, you can directly set it to your server socket's fd (since it is probably the first of the monitored sockets, given socket numbers always increase), and iterate until it is equal to "nfds" (the currently highest fd).</li> </ol></li> <li>Not sure that it is mandatory, but before each call to <code>select</code>, you should clear (with FD_ZERO for example) and re-populate your read fd_set with all the sockets you want to monitor (i.e. your server socket and all your clients sockets). Once again, inspire yourself of the Wikipedia example.</li> </ol>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload