1

I'm struggling to understand what's happening in this two scenarios:

  1. I have a udpClient that sends messages to a remote host. I create the client and then call the Send() method specifying the remote host to which send the data.

  2. I have a udpClient that sends messages to a remote host. I create the client and call the Connect() method to avoid to specify the remote host to which send the data in the Send() method, indeed from the documentation: "The Connect method establishes a default remote host using the value specified in the endPoint parameter. Once established, you do not have to specify a remote host in each call to the Send method."

The udpClient is created in the same way:

private static UdpClient CreateUdpClient(IPAddress localNetworkAdapter, IPEndPoint addressForReadingData)
        {
            var client = new UdpClient();
            client.Client.ExclusiveAddressUse = false;
            client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            client.Client.Blocking = false;
            client.Client.Ttl = 10;
            client.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 10);
            client.Client.Bind(new IPEndPoint(localNetworkAdapter, 0));
            client.Connect(addressForReadingData);
            return client;
        }

Everything works fine but if I cut the network connectivity and then reconnect the network:

  1. In the first scenario everything works fine.

  2. in the second one a SocketException (10022 - An invalid argument was supplied) is thrown every time the Send() method is called.

Since the UDP protocol is connectionless and the Connect() method provides just a way to not specify the remote host in each Send() call, I'm wondering what the difference between this two scenarios. In order to let the the second scenario works I have to close the client and then recreate/reconnect it.

I wrote a simple test code to prove this behavior, just change the scenario variable to change between the two scenarios.

  1. If scenario == false the console print an error message as long as the connectivity is down but will start to print "Sent" when the connectivity comes back
  2. If scenario == true you will see error messages keep going to be printed even if the connectivity came back
using System.Net;
using System.Net.Sockets;

namespace UdpTester
{
    static class Program
    {
        static void Main(string[] args)
        {
            // scenario 1 -> false
            // scenario 2 -> true
            bool scenario = true;
            
            IPEndPoint remoteHost = new IPEndPoint(IPAddress.Parse("172.30.65.8"), 3000);
            IPAddress localNetworkAdapter = IPAddress.Parse("172.30.65.3");
            ushort udpMaxPacketSizeInBytes = 1400;

            Console.WriteLine("Starting UDP tester:");
            Console.WriteLine($"Remote host: {remoteHost}");
            Console.WriteLine($"Network adapter: {localNetworkAdapter}");
            Console.WriteLine($"Max packet size (Bytes): {udpMaxPacketSizeInBytes}");

            var udpClient = CreateClient(localNetworkAdapter, remoteHost, udpMaxPacketSizeInBytes, scenario);

            SendData(udpClient, remoteHost, scenario);
        }

        static UdpClient CreateClient(IPAddress localNetworkAdapter, IPEndPoint remoteHost, int bufferSize, bool scenario)
        {
            var client = new UdpClient();
            client.Client.ExclusiveAddressUse = false;
            client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
            client.Client.SendBufferSize = bufferSize;
            client.Client.Blocking = false;
            client.Client.Ttl = 10;
            client.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 10);
            client.Client.Bind(new IPEndPoint(localNetworkAdapter, 0));
            if(scenario)
                client.Connect(remoteHost);
            return client;
        }

        static void SendData(UdpClient client, IPEndPoint remoteHost, bool scenario)
        {
            Console.WriteLine("\nSending data...");
            while (true)
            {
                try
                {
                    if(scenario)
                        client.Send(new byte[1], 1);
                    else
                        client.Send(new byte[1], 1, remoteHost);                        
                    Thread.Sleep(500);
                    Console.WriteLine("Sent");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
            }
        }
    }
}

Thanks for the help,
Regards

  • It's most likely due to some ICMP messages, e.g. [this question](https://stackoverflow.com/questions/74327225/why-does-sending-via-a-udpclient-cause-subsequent-receiving-to-fail/74327430#74327430). Because the `Connect` method allows the OS to know which socket can handle remote errors. – shingo Jun 09 '23 at 10:01
  • Dispose your client with `using var udpClient =...`. Also you should use `IPAddress.Any` for the local address. – Charlieface Jun 09 '23 at 10:14

0 Answers0