Networking and Communication
Socket.Select ignores timeout and returns immediately.
Question:
I'm writing an application that I want to listen on a UDP socket and to wake up every time a message is received so it can process it, and to also wake up after if a certain time out has expired so it can do some book keeping and various other tasks, and then loop round again.
Below is quick sample to show the problem. From what I've always understood of Select, and what the documentation says, it should sleep for up to the time out (5s here) waiting for data, but it doesn't. It just returns immediately whether there's data or not - though the collection is empty when there's no data so that part of it is correct. The end result is this is a constant loop, CPU usage goes to 100% and is just generally bad. I could put in a Sleep, but that wouldn't be able to wake up when a packet is received. I could make use of threads, or asynchronous calls, but it all seems to be a completed work around for something that should just work.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim m_Socket As Socket
Dim BindAddr As IPEndPoint
Dim FromAddr As IPEndPoint
Dim Sockets As New Collection
Dim Buffer(512) As Byte
m_Socket = New Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
BindAddr = New IPEndPoint(IPAddress.Parse("192.168.130.67"), 5000)
m_Socket.Bind(BindAddr)
While True
Sockets.Clear()
Sockets.Add(m_Socket)
' Should pause here for 5s when no data, but doesn't.
Socket.Select(Sockets, Nothing, Nothing, 5000)
If Sockets.Count > 0 Then
m_Socket.Receive(Buffer, 512, SocketFlags.None)
' Process packet and send any replies, etc.
End If
' Do other book keeping tasks here.
End While
End Sub
I've also written a quick C sample to do a similar think incase it was some problem with UDP sockets, but the C version works - it pauses for 5s when there's no data to read;
#include <windows.h>
#include <winsock.h>
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET m_Socket;
sockaddr_in BindAddr;
int FromLen;
sockaddr_in FromAddr;
char Buffer[ 512 ];
fd_set Sockets;
timeval Wait = { 5, 0 };
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 2, 2 );
WSAStartup( wVersionRequested, &wsaData );
m_Socket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
BindAddr.sin_family = AF_INET;
BindAddr.sin_addr.s_addr = inet_addr( "192.168.130.67" );
BindAddr.sin_port = htons( 5000 );
bind( m_Socket, (SOCKADDR*)&BindAddr, sizeof( BindAddr ) );
while( true )
{
FD_ZERO( &Sockets );
FD_SET( m_Socket, &Sockets );
// Correctly waits here for 5s.
if( select( 0, &Sockets, NULL, NULL, &Wait ) > 0 )
{
FromLen = sizeof( FromAddr );
recvfrom( m_Socket, Buffer, sizeof( Buffer ), 0, (SOCKADDR*)&FromAddr, &FromLen );
printf( "READ" );
// Process packet and send any replies, etc
}
// Book keeping stuff here.
}
closesocket( m_Socket );
return 0;
}
Any thoughts on why the VB version doesn't work? I'd have thought it just wraps the standard API Select call, so should work, but doesn't seem too. Some property I'm missing?
Thanks in advance.
Answer1:
Any chance the VB version returns after 5ms?
From MSDN:
Socket.Select
Answer2:
OhGod wrote: |
From what I've always understood of Select, and what the documentation says, it should sleep for up to the time out (5s here) waiting for data, but it doesn't. It just returns immediately whether there's data or not - though the collection is empty when there's no data so that part of it is correct.
|
|
Not 5 Seconds but 5 Micro Seconds, See MSDN documenation again.
I hope this will help.
Best Regards,
Rizwan aka RizwanSharp
WPF Learning Series @ http://geekswithblogs.net/RizwanSharp :: Microsoft MVP - Visual Developer, C#
Answer3:
*cough* Uh..yeah, that'll be it.
I read it as milliseconds, not microseconds, for some reason, hence the 5000 for a 5 second delay. Fixed now, cheers.
Answer4:
I have the same problem, with UDP sockets and infinite timeout. Here's the snippet:
Code SnippetAnswer5:
I have exactly the same problem. I'd love to know why the -1 timeout value does not work as documented. I've resorted to putting the whole thing in a loop with a ridiculously long delay.
Do
' Clear the select lists
RRL.Clear()
ERL.Clear()
' Add all connections to the select lists
RRL.AddRange(_ConnReg.GetConnectionList())
ERL.AddRange(RRL)
' Monitor sockets for accept-ready/read-ready and error conditions
' Note: The docs say a timeout of '-1' waits forever. However, it lies
Socket.Select(RRL,
Nothing, ERL, 1000000000)
Loop While RRL.Count = 0 And ERL.Count = 0 And Not _Abort
Answer6:
Yup, looks like a bug. Someone should open a bug at http://connect.microsoft.com/.... I've stepped through the code with windbg and so I'll do it unless anyone beats me to it. Winsock's select[1] says "If time-out is a null pointer, select will block indefinitely", however in the -1 case Socket.Select incorrectly passes a reference to a timeval struct (which has a zero timeout value).
[1] "select (Windows)" http://msdn2.microsoft.com/en-us/library/ms740141.aspx
http://www.alanjmcf.me.uk/ Please follow-up in the newsgroup. If I help, mark the question answered
Answer7:
I've created a bug at connect.microsoft.com. See https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=286646 Add your votes, validation, and comments to it.
http://www.alanjmcf.me.uk/ Please follow-up in the newsgroup. If I help, mark the question answered
Answer8:
The bug has been verified:
So how quick till it is fixed... Will it make Orcas release?
http://www.alanjmcf.me.uk/ Please follow-up in the newsgroup. If I help, mark the question answered
Answer9:
Still doesn't look like there's a fix. I've installed 3.5 and my code still fails to Select correctly on infinity. Debugging their code shows that it is still using an uninitialised TimeValue.
Anyone got any ideas?
FYI who noticed the workaround on the connect website, they suggest passing -2 for a value of >1 hour 
Related posts
Powered by BlogEngine.NET 1.2.0.0
Sponsor