UDP client throw a SocketException (10022) on Send after network reconnection

Federico 0 Reputation points
2023-06-09T08:00:21.15+00:00

Hi,

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;

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

C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,542 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Anonymous
    2023-06-12T08:02:06.2+00:00

    Hi @Federico , Welcome to Microsoft Q&A.

    First case: In the first case, you create a udpClient and use the Send() method to specify the remote host every time you send a message. The client in this way is connectionless, which means it doesn't care about the state or connectivity of the remote host. When you disconnect from the network and reconnect, the client can still send messages because each send specifies the address of the remote host and does not depend on the previous connection state.

    Second case: In the second case, when you call the Connect() method, it sets the default remote host for the UdpClient instance, but does not establish a connection in the traditional sense. UDP is still a connectionless protocol, and each individual UDP datagram is independent and can be sent to any valid remote endpoint. The Connect() method in UdpClient is mainly used as a convenience to avoid specifying the remote host for each Send() call. But when the network connection is interrupted and reconnected, the "connection" previously established through the Connect() method will be invalidated because the underlying network state has changed. This is why subsequent calls to Send() with an invalid connection result in a SocketException with an error code indicating an invalid parameter.

    If you want to solve the error in the second case, you can also re-connect to establish a new connection.

    client.Close(); // close the existing connection
    client.Connect(addressForReadingData); // establish a new connection
    

    Best Regards,

    Jiale


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment". 

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.