43

I am wondering whether I can set a timeout value for UdpClient receive method.

I want to use block mode, but because sometimes udp will lost packet, my program udpClient.receive will hang there forever.

any good ideas how I can manage that?

Jack
  • 3,913
  • 8
  • 41
  • 66

5 Answers5

67

There is a SendTimeout and a ReceiveTimeout property that you can use in the Socket of the UdpClient.

Here is an example of a 5 second timeout:

var udpClient = new UdpClient();

udpClient.Client.SendTimeout = 5000;
udpClient.Client.ReceiveTimeout = 5000;

...
famousgarkin
  • 13,687
  • 5
  • 58
  • 74
sep15ms
  • 879
  • 1
  • 8
  • 6
  • 6
    This only works if you are doing a synchronous send/receive. For ansynchronous calls, you could use `Task.Delay` to create your own timeout, e.g. `Task.WhenAny(udpClient.ReceiveAsync(), Task.Delay(5000))`; – AJ Richardson May 31 '17 at 20:16
  • Well of course! How did I miss that simple solution! Thanks for your comment AJ! – Jörgen Sigvardsson Nov 10 '17 at 10:57
  • @AJRichardson well, I don't think that is a good way to go, 'cause when the timer -ask completed the process will resume BUT udpClient.ReceiveAsync() will still be on waiting... I would suggest maybe something like: Task.WaitAny(new[] { udpClient.ReceiveAsync() }, waitTimeOutInMs); – Ivandro Jao Sep 12 '20 at 20:13
  • 1
    @IvandroJao You are correct, although I don't know that your code will fix the issue. It sounds like you should close the socket in the timeout case: see https://stackoverflow.com/a/12642359/1299394 – AJ Richardson Sep 13 '20 at 13:40
37

What Filip is referring to is nested within the socket that UdpClient contains (UdpClient.Client.ReceiveTimeout).

You can also use the async methods to do this, but manually block execution:

var timeToWait = TimeSpan.FromSeconds(10);

var udpClient = new UdpClient( portNumber );
var asyncResult = udpClient.BeginReceive( null, null );
asyncResult.AsyncWaitHandle.WaitOne( timeToWait );
if (asyncResult.IsCompleted)
{
    try
    {
        IPEndPoint remoteEP = null;
        byte[] receivedData = udpClient.EndReceive( asyncResult, ref remoteEP );
        // EndReceive worked and we have received data and remote endpoint
    }
    catch (Exception ex)
    {
        // EndReceive failed and we ended up here
    }
} 
else
{
    // The operation wasn't completed before the timeout and we're off the hook
}
Brad Nabholz
  • 2,378
  • 20
  • 20
  • This was a long time ago! That looks ok now. WaitOne also returns a result you can use to determine if it timed out. – weston Jul 09 '14 at 21:50
4

Actually, it appears that UdpClient is broken when it comes to timeouts. I tried to write a server with a thread containing only a Receive which got the data and added it to a queue. I've done this sort of things for years with TCP. The expectation is that the loop blocks at the receive until a message comes in from a requester. However, despite setting the timeout to infinity:

_server.Client.ReceiveTimeout = 0; //block waiting for connections
_server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0);

the socket times out after about 3 minutes.

The only workaround I found was to catch the timeout exception and continue the loop. This hides the Microsoft bug but fails to answer the fundamental question of why this is happening.

famousgarkin
  • 13,687
  • 5
  • 58
  • 74
Pierre
  • 114
  • 4
3

There is a ReceiveTimeout property you can use.

Filip Ekberg
  • 36,033
  • 20
  • 126
  • 183
3

you can do like this:

udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);
Elyas Nategh
  • 540
  • 6
  • 5