Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to recover gracefully from a C# udp socket exception

Tags:

c#

sockets

udp

Context: I'm porting a linux perl app to C#, the server listens on a udp port and maintains multiple concurrent dialogs with remote clients via a single udp socket. During testing, I send out high volumes of packets to the udp server, randomly restarting the clients to observe the server registering the new connections. The problem is this: when I kill a udp client, there may still be data on the server destined for that client. When the server tries to send this data, it gets an icmp "no service available" message back and consequently an exception occurs on the socket.

I cannot reuse this socket, when I try to associate a C# async handler with the socket, it complains about the exception, so I have to close and reopen the udp socket on the server port. Is this the only way around this problem?, surely there's some way of "fixing" the udp socket, as technically, UDP sockets shouldn't be aware of the status of a remote socket?

Any help or pointers would be much appreciated. Thanks.

like image 791
Gearoid Murphy Avatar asked Apr 10 '10 12:04

Gearoid Murphy


1 Answers

I think you are right in saying: 'the server should not be aware'. If you send an UDP packet to some IP/port which may or may not be open, there is no way of knowing for the server if it reached it's destination.

The only way for the server to know is to have the client send an ACK back. (Also both the client and server must have resend mechanisms in place in cases of lost packages).

So clearly something else is going on in your code (or with the .Net udp implementation)

EDIT:

After Nikolai's remark I checked the docs. And indeed there is a distinction in .Net to about being 'connected' or 'connectionless' when using UDP.

If you use code like this:

UdpClient udpClient = new UdpClient(11000); //sourceport
try{
     udpClient.Connect("www.contoso.com", 11000); //'connect' to destmachine and port
     // Sends a message to the host to which you have connected.
     Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
     udpClient.Send(sendBytes, sendBytes.Length);

then apparently you are 'connected'

However if you use code like this:

     UdpClient udpClientB = new UdpClient();
     udpClientB.Send(sendBytes, sendBytes.Length, "AlternateHostMachineName", 11000);

then you can send to whomever you choose without 'connecting'.

I'm not sure what your code looks like, but it might be worthwhile to check if you are using the correct set of commands which doesn't assume a 'connection'

like image 172
Toad Avatar answered Sep 27 '22 19:09

Toad