Jump to content
  • Advertisement
jakubp

Grouping asynchronously received UDP packets together, am I doing it right?

Recommended Posts

As it is my first post in this forum, I want to say hello to everyone.

Firstly I will tell what I want to acheive, then I will provide some example. So, I'm writing game in c# using MonoGame Framework and my own ECS. It's first time when I try to implement multiplayer feature. In my ECS every system is run one by one and order of systems is important. So I tough that the easiest way to implement networking, will be to receive packets asynchronously and group them together every frame. When client system would be executed every packet, which was collected since last frame would be read and used to update game state. But I don't have experience in asynchronous programming, so it's hard for me to combine asynchronous and synchronous part.

Note, it's not my real production code, only example.

using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Threading.Tasks;

public class ReceiveServerData
{
    private IList<byte[]> LocalPackets;

    private IList<byte[]> GlobalPackets;

    public ReceiveServerData(IList<byte[]> globalPackets)
    {
        GlobalPackets = globalPackets;
        LocalPackets = new List<byte[]>();

        Init();
    }

    public void Init()
    {
        Task.Run(async () =>
        {
            using (var udpClient = new UdpClient(11000))
            {
                while (true)
                {
                    var result = await udpClient.ReceiveAsync();

                    LocalPackets.Add(result.Buffer);
                }
            }
        });
    }

    public void Update()
    {
        GlobalPackets.Clear();

        //-----Can this process be interrupted, by ReceiveAsync? ----
        var localCopy = LocalPackets.ToList(); 
        LocalPackets.Clear();                   
        //----- If yes some packets may be lost due to poor design?

        foreach(var packet in localCopy)
        {
            GlobalPackets.Add(packet);
        }
    }
}

My problem with this code, is that, if I understand correctly, asynchronous code can be executed in any moment, so if the process of rewriting local packets to global packets will be interrupted, packets which was received during this interruption will be lost. I know that when using UDP I should expect some packets to be lost, but here packets will be lost not due to some network problem but because of how code is designed. For me it's indication that something is wrong with my code and design. Also, I use Global packets so every other system after this one, is safe to use GlobalPackets because they will not change until next synchronous update.

Note 2, I want to keep things simple, I'm making this game as a learning experience and I don't want to bother my head with complex network design patterns. Firstly, I want to make it work :)

Share this post


Link to post
Share on other sites
Advertisement

You can take two routes:

1) Don't use threads. Instead, set the UDP socket to non-blocking mode, and at the beginning of each tick, read from the UDP socket until it returns "no more data." (The kernel will buffer a fair amount; you can control how much with a socket option.) No threads needed!

2) Use threads, and add a lock around the "swap global for local" operation. Specifically, when you add to the local list, you need to hold the lock while inserting into the list. When you call into the receiver object from your main thread, grab the lock, clear the global list, swap the global and local list variables, release the lock, and return the global list (which is now full of what's been received.)

EIther system will work. Also, you don't need async/await at all in this code, because the reading thread can just block in the UDP socket receive function.

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!