HaMster
HaMster

Reputation: 543

How to do async udp networking right?

As many others here on SO I'm trying to create a networking library. The requirements basically look like this:

Now after some reading about how to do this (most inspiring was Gaffer on Games) I set up my development environment, thought about how to do it and came up with this basic workflow:

  1. Initialize a socket and tell it to use "UDPv6"
  2. Bind that socket to a port and make exceptions not bother the user. There is a "Bound" propery that tells him that the socket is set up correctly.
  3. Find out about the max MTU the NICs on the local machine support.
  4. Initialize a number of SocketAsyncEventArgs, tell its Completed event to call the private dispatch method and set its buffer to the size of the max MTU from step 3.
  5. Call the Sockets ReceiveFromAsync method with the first SAEA object around.

When data comes in, I do the following:

  1. Call the ReceiveFromAsync method with the next free SAEA object
  2. Get buffer and Sender information from the current SAEA object and make it available again
  3. Fire a new event with the received message.

I did some testing on this approach and it is working quite good. I fired a message at it every 10 milliseconds with 200 bytes of data for 10000 cycles and there is pretty much no increase in CPU or memory load. Only NIC load is increasing. However I came up with some problems | questions:

The library will hopefully be of use to someone else one day and it's repository is publicly available. As of this question, the current commit can be found here

Upvotes: 0

Views: 3327

Answers (1)

Jacob
Jacob

Reputation: 3698

Wow, it is really huge subject. if you didn't learned about network sockets before you'd better learn. I can give you the gist but it is definitely not enough.

The Client:

public void Get()
    {
        string data;
        string input;
        IPEndPoint ipep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 9050);

        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


        try
        {
            socket.Connect(ipep);
        }
        catch (SocketException e)
        {
            Console.WriteLine("Unable to connect to server");
            Console.WriteLine(e.ToString());
            return;
        }

        NetworkStream ns = new NetworkStream(socket);
        StreamWriter sw = new StreamWriter(ns);
        StreamReader sr = new StreamReader(ns);

        data = sr.ReadLine();
        Console.WriteLine(data);

        while (true)
        {
            input = Console.ReadLine();
            if (input == "exite")
                break;

            sw.WriteLine(input);
            sw.Flush();

            data = sr.ReadLine();
            Console.WriteLine(data);
        }
        Console.WriteLine("Disconnected from server...");
        socket.Close();
        ns.Close();
        sr.Close();
        sr.Close();
    }

The Server:

public void Get()
    {
        string data;
        IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);

        Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        socket.Bind(ipep);
        socket.Listen(10);
        Console.WriteLine("Waiting for a client...");

        Socket client = socket.Accept();
        IPEndPoint newclient = (IPEndPoint)client.RemoteEndPoint;
        Console.WriteLine("Connected with: {0}, at Port: {1}", newclient.Address, newclient.Port);

        NetworkStream ns = new NetworkStream(client);
        StreamReader sr = new StreamReader(ns);
        StreamWriter sw = new StreamWriter(ns);

        string welcome = "Welcome to my test server";
        sw.Write(welcome);
        sw.Flush();

        while (true)
        {
            try
            {
                data = sr.ReadLine();
            }
            catch (IOException)
            {
                break;
            }
            Console.WriteLine(data);
            sw.WriteLine(data);
            sw.Flush();
        }
        Console.WriteLine("Disconnected from {0}", newclient.Address);
        sw.Close();
        ns.Close();
        sr.Close();
    }

Please try it out on Console application, see how it works.

Basically, the server opens the port (9050 in this example) waiting for the client connection then the client connects to the server and then starts the communication.

You mentioned you have to use UDP sockets, I presume you know about udp but if not you'd better check about the distinction between TCP and UDP especially about the way to verify that the data get to the desired destination (ad hoc concept and so on).

Upvotes: 0

Related Questions