views:

56

answers:

4

I'm currently working on a project which involves multiple clients connected to a server and waiting for data. I'm using select and monitoring the connection for incoming data. However, the client just continues to print nothing, acting as if select has discovered incoming data. Perhaps I'm attacking this wrong?

For the first piece of data the server does send, it is displayed correctly. However, the server then disconnects and the client continues to spew blank lines.

        FD_ZERO(&readnet);
        FD_SET(sockfd, &readnet);   
while(1){

            rv = select(socketdescrip, &readnet, NULL, NULL, &timeout);
            if (rv == -1) {
                perror("select"); // error occurred in select()
            } else if (rv == 0) {
                printf("Connection timeout!  No data after 10 seconds.\n");
            } else {
                // one or both of the descriptors have data
                if (FD_ISSET(sockfd, &readnet)) {
                    numbytes = recv(sockfd, buf, sizeof buf, 0);
                    printf("Data Received\n");
                    buf[numbytes] = '\0';
                    printf("client: received '%s'\n",buf);
                    sleep(10);
                }
            }
        }
+1  A: 

If I remember correctly, you need to initialise set of fds before each call to select() because select() corrupts it.

So move FD_ZERO() and FD_SET() inside the loop, just before select().

qrdl
Unfortunately, the same issue will still occur (I tried that earlier -- my apologizes for not mentioning in my initial question)
BSchlinker
+3  A: 

I think you need to check the result of recv. If it returns zero, I believe it means the server has closed the socket.

Also (depending on the implementation), you may need to pass socketdescrip+1 to select.

Mark Wilkins
If the server has closed the socket, why would select return a positive value? Wouldn't a socket closure result in a timeout from the client's perspective?
BSchlinker
@BSchlinker: On a close (at least with stream based sockets), I believe a signal is sent from the socket being closed to the other end resulting in select returning 1. The recv call returning zero indicates the other end was closed. My guess (it's a guess) on why select would continue to return >0 is that the "signal" still exists indicating the other end is closed. The recv apparently does not remove that signal (I'm misusing the term signal in this case a bit).
Mark Wilkins
Thanks for the explanation Mark -- I understand the overall gist now.
BSchlinker
This is correct. The reason is that `select` returning the socket as "readable" just means "a `read()` / `recv()` will not block", which is the case when the connection has been closed by the other end.
caf
A: 

Is this true when talking about your code?

select(highest_file_descriptor+1, &readnet, NULL, NULL, &timeout);

In your simple example (with FD_ZERO and FD_SET moved inside the while(1) loop as qrdl said) it should look like this:

select(sockfd+1, &readnet, NULL, NULL, &timeout);

Also - please note that when recv returns 0 bytes read it means that connection was closed - no more data! Your code is also buggy - when something bad happens on recv (it returns <0 when this happens) you will have serious trouble because something like buf[-1] may lead to unpredictable results. Please handle this case properly.

While I respect the fact that you try to use the low-level BSD sockets API I must say that I find it awfully inefficient. That's why I recommend to you if possible to use ACE which is a very efficient and productive framework which has a lot of things already implemented when it comes to network programming (ACE_Reactor for example is something that makes it easier to do what you're trying to achieve here).

Iulian Şerbănoiu
+1  A: 

acting as if select has discovered incoming data. Perhaps I'm attacking this wrong?

In addition to what was said before, I'd like to note that select()/poll() do tell you not when "data are there" but rather that next corresponding system call will not block. That's it. As was said above, recv() doesn't block and properly returns 0, what means EOF, connection was closed by the other side.

Though on most *nix systems in the case only first call of recv() would return 0, following calls would return -1. When using async I/O rigorous error checking is a must!

And personally I would strongly suggest to use poll() instead. Unlike select(), it doesn't destroy its arguments and works fine with high numbered socket descriptors.

Dummy00001