C Programming
 
Forums: » Register « |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support | 
User Name:
Password:
Remember me
Go Back   Dev Shed ForumsProgramming LanguagesC Programming

Reply
Add This Thread To:
  Del.icio.us   Digg   Google   Spurl   Blink   Furl   Simpy   Y! MyWeb 
Thread Tools Search this Thread Rate Thread Display Modes
 
Unread Dev Shed Forums Sponsor:
  #1  
Old July 10th, 2003, 10:55 AM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
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

Reply With Quote
  #2  
Old July 10th, 2003, 11:32 AM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538
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 11:35 AM.

Reply With Quote
  #3  
Old July 10th, 2003, 01:52 PM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
>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

Reply With Quote
  #4  
Old July 10th, 2003, 02:50 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538
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):
Quote:
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/d...ror_codes_2.asp .

Last edited by dwise1_aol : July 10th, 2003 at 02:59 PM.

Reply With Quote
  #5  
Old July 11th, 2003, 12:05 PM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
Excellent- you were right, it is returning an error- specifically WSAEINVAL which, according to msdn, means:
Quote:
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

Reply With Quote
  #6  
Old July 11th, 2003, 12:40 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538
Quote:
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:
Quote:
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


Reply With Quote
  #7  
Old July 11th, 2003, 12:55 PM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
Thanks for the idea- I wish all cursory treatment would be as well-referenced .

Bill

Reply With Quote
  #8  
Old July 11th, 2003, 01:28 PM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538
Quote:
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.

Reply With Quote
  #9  
Old July 14th, 2003, 07:42 AM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
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

Reply With Quote
  #10  
Old July 14th, 2003, 10:40 AM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538
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.

Reply With Quote
  #11  
Old July 15th, 2003, 09:16 AM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
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

Reply With Quote
  #12  
Old July 15th, 2003, 09:59 AM
ueberbill ueberbill is offline
Junior Member
Dev Shed Newbie (0 - 499 posts)
 
Join Date: Jun 2003
Location: Georgia
Posts: 20 ueberbill User rank is Just a Lowly Private (1 - 20 Reputation Level) 
Time spent in forums: < 1 sec
Reputation Power: 0
Send a message via AIM to ueberbill
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?

Reply With Quote
  #13  
Old July 15th, 2003, 11:24 AM
dwise1_aol's Avatar
dwise1_aol dwise1_aol is offline
Contributing User
Dev Shed Expert (3500 - 3999 posts)
 
Join Date: Jan 2003
Location: USA
Posts: 3,976 dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level)dwise1_aol User rank is Colonel (50000 - 60000 Reputation Level) 
Time spent in forums: 1 Month 4 Days 4 h 43 m 23 sec
Reputation Power: 538