|
|
|||||||||
|
|||||||||
| |||||||||
|
|
|
| |||||||||
![]() |
|
|
«
Previous Thread
|
Next Thread
»
|
Thread Tools | Search this Thread | Rate Thread | Display Modes |
|
#1
|
|||
|
|||
|
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
|
||||
|
||||
|
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. |
|
#3
|
|||
|
|||
|
>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 |
|
#4
|
||||
|
||||
|
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:
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. |
|
#5
|
|||
|
|||
|
Excellent- you were right, it is returning an error- specifically WSAEINVAL which, according to msdn, means:
Quote:
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 |
|
#6
|
||||
|
||||
|
Quote:
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:
|
|
#7
|
|||
|
|||
|
Thanks for the idea- I wish all cursory treatment would be as well-referenced
.Bill |
|
#8
|
||||
|
||||
|
Quote:
Thank the modern miracle of copy-and-paste. Hope it helps. |
|
#9
|
|||
|
|||
|
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 |
|
#10
|
||||
|
||||
|
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. |
|
#11
|
|||
|
|||
|
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 |
|
#12
|
|||
|
|||
|
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?
|
|
#13
|
||||
|