Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0

    select() timeout not working


    Howdy,

    I'm trying to get select to block for 10 seconds listening on my socket and then break out so I can check stdin. The only problem is, select seems to think that there is data present when recv tells me there is none (although isn't recv supposed to block? It doesn't on runtime here). I'm developing this in Cygwin on a WinXP box, and I'm using winsock.h and wsock32.dll.

    Here's what should be the relevant parts of my code, listenset is an fd_set (as defined by winsock.h) and listentimeout is a struct timeval.

    Code:
        FD_ZERO(listenset);
        FD_SET(mySocket,listenset);
    
        (*listentimeout).tv_sec = 10;
        (*listentimeout).tv_usec = 0;
      
        r_value = select(1,listenset,NULL,NULL,listentimeout);
        if(r_value){
          printf("Data to be listened to\n");
          r_value = recv(mySocket,recvbuffer,100,0);
          if(r_value>0){
            printf("Got data\n");
            printf("Recvbuffer: %s\n",recvbuffer);
          }
          else
            printf("no data\n");
        }
    I had thought the tv_sec values should be the delta since 1 Jan 1970, but I saw an example that just used the number of seconds to wait. I've tried it both ways and neither results in any waiting by select. On runtime, the loop executes and prints out:

    Data to be listened to
    no data

    Over and over again, with no waiting.

    Any ideas?

    Thanks,
    Bill
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    I've used select before under Windows and it worked just fine for me. So the best I can suggest is some more stuff to test.

    What are the actual declarations for listenset and for listentimeout? select requires pointers to fd_set and to struct timeval, which you don't appear to be giving it unless they are actually declared as pointers. And if they are pointers, has memory been allocated to them?

    select returns either the number of file descriptors (sockets in our case) ready, or zero if timed out, or -1 if an error. Have you tested the value of r_value? It looks like it could only be 1, but it wouldn't hurt to verify that.

    Also, have you tested that your socket is the one that is set (yes, I know there is only one). Try the FD_ISSET macro on it:
    Code:
    if (FD_ISSET (mySocket,listenset))
        printf("mySocket ready\n");
    else
        printf("mySocket is not ready\n");
    And the timeout value is indeed the length of the timeout itself, not the time since 1970. So the second ("but I saw an example that just used the number of seconds to wait") is what you want to use.

    AFTERTHOUGHT:
    And I assume that you know not to use select to look for input from stdin -- it didn't look like you were trying that. It's a neat trick to use in UNIX/Linux, where almost everything is a file. But files and sockets are different beasties in Windows/DOS that have to handled separately, so that trick wouldn't work here. Just mentioning it in case you were trying it or thinking about it.
    Last edited by dwise1_aol; July 10th, 2003 at 10:35 AM.
  4. #3
  5. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    >What are the actual declarations for listenset and for >listentimeout?

    My declarations:
    fd_set *listenset;
    struct timeval *listentimeout;
    listenset = (fd_set *)malloc(sizeof(struct fd_set));
    listentimeout = (struct timeval *)malloc(sizeof(struct timeval));

    >Have you tested the value of r_value?
    r_value equals -1 every time.

    Adding your macro in, the app prints out "mySocket ready" every time it loops.

    And I actually did try to get input from stdin when I was testing select (which, as you could have told me, didn't work). Now, however, I'm trying to get data out of mySocket, which is indeed a socket.

    I'm stumped, but thanks for your help- with this and my previous questions.

    Bill
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    GA, I think we have an error. That is, since select is returning a -1 every time, it is reporting an error every time.

    Here's what VC++5 help says about select's return value (quoted here since we're dealing with Winsock):
    Return Values
    The select function returns the total number of socket handles that are ready and contained in the FD_SET structures, zero if the time limit expired, or SOCKET_ERROR if an error occurred. If the return value is SOCKET_ERROR, WSAGetLastError can be used to retrieve a specific error code.

    Error Codes
    WSANOTINITIALISED
    A successful WSAStartup must occur before using this function.

    WSAEFAULT
    The Windows Sockets implementation was unable to allocated needed resources for its internal operations, or the readfds, writefds, exceptfds, or timeval parameters are not part of the user address space.

    WSAENETDOWN
    The network subsystem has failed.

    WSAEINVAL
    The timeout value is not valid, or all three descriptor parameters were NULL.

    WSAEINTR
    The (blocking) call was canceled through WSACancelBlockingCall.

    WSAEINPROGRESS
    A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.

    WSAENOTSOCK
    One of the descriptor sets contains an entry that is not a socket.
    I'd be willing to bet that the value of SOCKET_ERROR is -1.

    I just looked at your code again and I see where an error condition would be misinterpreted as an indication of incoming data. Here's a possible rewrite of your code:
    Code:
      
        r_value = select(1,listenset,NULL,NULL,listentimeout);
        if(r_value == SOCKET_ERROR)
        {
            printf("Error %d occured\n",WSAGetLastError());
        }
        else if (r_value > 0)
        {
            r_value = recv(mySocket,recvbuffer,100,0);
            if(r_value>0)
            {
                printf("Got data\n");
                printf("Recvbuffer: %s\n",recvbuffer);
            }
            else
                printf("no data\n");
        }
    This way you will only try to read from the socket when you are sure that there is data there. Also this way, you will report when an error occurs and what that error is. There is list of WSA error numbers and what they mean, but it's hard to find in the VC++ help pages. Just the other day in another thread, messorian gave a link to that list on the MSDN site, http://msdn.microsoft.com/library/de...or_codes_2.asp .
    Last edited by dwise1_aol; July 10th, 2003 at 01:59 PM.
  8. #5
  9. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    Excellent- you were right, it is returning an error- specifically WSAEINVAL which, according to msdn, means:
    Invalid argument.
    Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening.
    I don't understand how calling select could pass an invalid argument to anything having to do with the socket so does this means there's something off with the 'current state of the socket'? This is a connectionless socket, which might help.

    Bill
  10. #6
  11. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    Originally posted by ueberbill
    Excellent- you were right, it is returning an error- specifically WSAEINVAL which, according to msdn, means:


    I don't understand how calling select could pass an invalid argument to anything having to do with the socket so does this means there's something off with the 'current state of the socket'? This is a connectionless socket, which might help.

    Bill
    I had never tried select with a udp socket, since all my udp servers have been simple and quite content to block on recvfrom.

    Have you considered trying to use a non-blocking socket? Here's some sample code:
    Code:
       unsigned long nonblocking = 1;    /* Flag to make socket nonblocking */
    
        /* Create a best-effort datagram socket using UDP */
        if ((sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
            DieWithError("socket() failed");
    
        /* Set the socket to nonblocking */
        if (ioctlsocket(sock, FIONBIO, &nonblocking) != 0)
            DieWithError("ioctlsocket() failed");
    
        /* Receive a datagram */
        for (;;)
        {
            if ((recvStringLen = recvfrom(sock, recvString,
                     MAXRECVSTRING, 0, NULL, 0)) < 0)
            {
                if (WSAGetLastError() != WSAEWOULDBLOCK)
                    DieWithError("recvfrom() failed");
                else
                {
                    printf("Still have not received packet...Waiting and then trying again\n");
                /* could check stdin at this point or wherever */
                    Sleep(2000);  /* Sleep for 2 milliseconds */
                }
            }
            else
               /* process received message */
        }
    Sorry for the cursory treatment, but I've got to get back to work. Basically, a "blocking" function working on a non-blocking socket will return with an error if it would have blocked. So you would expect to get lots of WSAEWOULDBLOCK "errors".

    Here's a short discussion from a FreeBSD forum (http://dbforums.com/arch/186/2003/6/813609) that might help even though it is UNIX:
    David Schwartz
    Jun 11 2003 11:40 "Rainer Temme" wrote in message
    news:bc6q1q$n83$1@news.mch.sbs.de...


    > Using UDP there is no guarantee, that the packets are received
    > by the remote-side (regardless if you use select() or not).
    > select() might however be useful (when checking if the
    > socket is writeeable) to prevent from running into
    > a rescource-shortage (for example if you try to write more
    > packets than the connection to the remote-side can deliver,
    > and if you do this over a longer period of time. In this
    > case, the local IP-implementation will buffer a certain amount
    > of packets locally. If this buffer is full, nor more packets are
    > accepted to be sent from this socket...and so (hopefully) select
    > would indicate, that the socket is not writable in that moment.)
    > (sendto() would return an error if you would try to send data in
    > this moment as well)

    Note however that this "buffer" is NOT a socket send queue. So if
    'sendmsg' returns EWOULDBLOCK, do not select for write again immediately. If
    you do that, you'll just burn the CPU. If you use UDP, you are responsible
    for transmit pacing. You can't foist this responsibility onto the kernel.

    In general, I'd advise you just to not bother 'select'ing on UDP sockets
    for writability. Use non-blocking socket operations and if you get
    'EWOULDBLOCK', just take it as an indication that you're sending too fast,
    just as you would if you get packet loss.

    Note that getting 'EWOULDBLOCK' on an unconnected UDP socket during a
    'sendmsg' operation only means that writes *to* *that* *destination* will
    block.

    David Schwartz
    Jun 11 2003 16:38 "liuzixing" wrote in message
    news:32d9df08.0306110015.2a7fa191@posting.google.com...


    > hello,
    > I know that select() must be used to send data via various tcp sockets.
    > But I want to ask:
    > If I want to send/receive data to/from different hosts via the same udp
    socket,
    > select() on this socket must be used ?
    > If I send out the data directly when data is ready, will this succeed?
    > Any suggest is welcome.
    > hugh.liu

    Make the socket non-blocking and treat 'EWOULDBLOCK' as a dropped packet
    (that is, do not retry immediately, reschedule instead). Using 'select' for
    write on an unconnected UDP socket is a bad idea anyway, since the system
    has no idea which network interface the packet is going to be sent on.

    DS
  12. #7
  13. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    Thanks for the idea- I wish all cursory treatment would be as well-referenced :).

    Bill
  14. #8
  15. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    Originally posted by ueberbill
    Thanks for the idea- I wish all cursory treatment would be as well-referenced :).

    Bill
    Thank the modern miracle of copy-and-paste.

    Hope it helps.
  16. #9
  17. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    Alas I can't seem to get the nonblocking socket to work, either- here's the code I'm using:

    Code:
      unsigned long nonblocking = 1;    /* Flag to make socket nonblocking */
    
      /* Create a best-effort datagram socket using UDP */
      if ((mySocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0){
        DieWithError("socket() failed");
      }
      /* Set the socket to nonblocking */
      if (ioctlsocket(mySocket, FIONBIO, &nonblocking) != 0){
        DieWithError("ioctlsocket() failed");
      }
    
      /* Receive a datagram */
      while (1){
        /*   if ((r_value = recvfrom(mySocket, recvbuffer,MAXBYTES, 0, NULL, 0)) <\
     0)
        */
        if( (recv(mySocket,recvbuffer,100,0))<0)
          {
            if (WSAGetLastError() != WSAEWOULDBLOCK){
              DieWithError("recv() failed");
            }
            else
              {
                printf("Still have not received packet...Waiting and then trying ag\
    ain\n");
                /* could check stdin at this point or wherever */
                Sleep(2000);  /* Sleep for 2 milliseconds */
              }
          }
        else{
            /* process received message */
        }
    The loop executes only once with the error "recv() failed" printed out. I've also tried using recvfrom (as in your sample code) but it does the same thing. Does this mean that, although it makes it through the if statement, ioctlsocket isn't working properly? The article you reference refers to EWOULDBLOCK, but only in relation to writing to a nonblocking socket, not reading from it.

    Thanks,
    Bill
  18. #10
  19. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    What error does it return?

    Also, for udp you'd probably want to stick with recvfrom, at least until we get this solved. As I understand, you can use recv, but I forget what that buys you or what you might need to look out for. Besides, recvfrom will get you the client's address.
  20. #11
  21. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    Sorry, don't know why I didn't include that- it's WSAEINVAL again. It seems if I can figure out why I'm getting that error I could go back to my original code with select().

    I'll stick to recvfrom().

    Thanks yet again,
    Bill
  22. #12
  23. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    An interesting side note- I just tried my original select() with timeout code on a SunOS 5.8 box and it waits and then stops blocking in a loop just like it should. Are there any windows specific issues with select?
  24. #13
  25. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    I'll compare your code snippet with a couple Winsock servers that use select and see if anything jumps out at me.

    Would you be opposed to zipping your source and posting it here? Or emailing it to me (I believe you can do so through the forum -- I've not tried it, but others have emailed me)? It's possible that the problem might be in another part of the code.
  26. #14
  27. No Profile Picture
    Junior Member
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Location
    Georgia
    Posts
    20
    Rep Power
    0
    Thanks very much for offering- here's a tar of my code and library (natagent.[hc]).

    Thanks again,
    Bill
    Attached Files
  28. #15
  29. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,158
    Rep Power
    2222
    Sorry for the delay.

    I compiled with the MinGW port of gcc and also with Visual C++v6.

    I had to change a couple things, like moving all the declarations to the top of the functions (this was in C) and commenting out the include for getopt.h for VC++6.

    In the while loop, you had commented out the assignments to listentimeout. You must reassign the timeout values before every time that you call select. This is because select modifies the contents of the timeout structure. I uncommented them.

    BTW, I also made the timeout period 5 seconds instead of 30, just to speed up the testing.

    The first time I ran using gcc, I didn't get any output once it had started the infinite loop with the select, so I had it output a "timed out" message.

    However, before I did that, I noticed an error. The prototype for select is:
    int select(int n, fd_set *readfds,fd_set *writefds,fd_set *exceptfds,struct timeval *timeout);

    You had coded:
    r_value = select(0,listenset,listenset,listenset,listentimeout);
    Looking back on your previous messages, you had correctly coded it as:
    r_value = select(1,listenset,NULL,NULL,listentimeout);
    You had also declared, but not used, two other fdset's.

    I tested all three combinations on both compilers and now get the same results:
    1. r_value = select(1,listenset,NULL,NULL,listentimeout);
    2. r_value = select(1,listenset,listenset,listenset,listentimeout);
    3. r_value = select(1,listenset,writeset,exceptset,listentimeout);

    1 and 3 work. That is to say, since I have no server to connect to, select returns a zero every 5 seconds (my timeout value).

    #2 does not work. select never seems to return at all. I don't know what problem is caused by using the same fdset in all three parameters, but it apparently causes select to hang up seriously and never return.

    Early on with VC6, select returned an error of 10038:
    WSAENOTSOCK
    (10038)
    Socket operation on non-socket.
    An operation was attempted on something that is not a socket. Either the socket handle parameter did not reference a valid socket, or for select, a member of an fd_set was not valid.
    I'm not sure what had caused that and I was not able to reproduce it.

    Hope that helps.

    PS
    I forgot to mention that you had left out the testing of the fdset after select returns with a positive value. This is especially important to do is you use more than one fdset parameters (case #3 above). You need to apply the macro FD_ISSET:
    if (FD_ISSET(mySocket,listenset))
    to ensure that that particular socket has something to receive.
    You cannot/should-not just assume that select returned with a positive value because of your socket, but you shoudl test for it explicitly.
    Last edited by dwise1_aol; July 17th, 2003 at 04:02 PM.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo