Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Have a look at our Games Focus blog post series which will show what Unity is doing for all game developers – now, next year, and in the future.
    Dismiss Notice

Maximum payload size

Discussion in 'Unity Transport' started by CyFy, Jul 6, 2022.

  1. CyFy

    CyFy

    Joined:
    Apr 4, 2019
    Posts:
    3
    Hi,

    I want to share serialized data over the network using Unity Transport. I also want to use the reliabile pipeline to ensure the data. Now the data can sometimes exceed the preconfigured maximum. So far I understand my problem, my issue now is, that I don't find the correct way, to increase the maximum size.



    What I did so far to create my pipeline:
    Code (CSharp):
    1. public static void InitNetwork(out NetworkDriver driver, out NetworkPipeline pipeline, bool simulator = false)
    2. {
    3.     var networkSettings = new NetworkSettings();
    4.     networkSettings.WithReliableStageParameters();
    5.     networkSettings.WithBaselibNetworkInterfaceParameters(maximumPayloadSize: 10000);
    6.    
    7.     driver = NetworkDriver.Create(networkSettings);
    8.     pipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
    9. }

    Edit 1:

    My send code currently looks like this:
    Code (CSharp):
    1. public void Send(string message)
    2. {
    3.    _driver.BeginSend(_pipeline, _connection, out var writer);
    4.    writer.WriteBytes(new NativeArray<byte>(Encoding.Default.GetBytes(message), Allocator.Temp));
    5.    _driver.EndSend(writer);
    6. }
    My server contains the following to handle messages:
    Code (CSharp):
    1. NativeArray<byte> payload = new NativeArray<byte>(stream.Length, Allocator.Temp);
    2. stream.ReadBytes(payload);
    3. Debug.Log($"Server: Got a message from a Client: {payload.Length}");
    With Send(new string('a', 1377)); the server receives the message.
    With Send(new string('a', 1378)); the server does not receive the message.


    Obsolete (had incomplete configuration for the fragmentation pipeline):
    I then added the FragmentationPipelineStage to my pipeline. It improved the situation somewhat. Now it works with a string up to 4096, which is a much more understandable length, but I still don't know, why it can't be more.
    Manually splitting the payload into chunks of 4096 bytes works. However I feel like there should be another way, espacially since the FragmentationPipelineStage is already part of the package.




    I also don't get an Error, the message just vanishes to dust, it seems.

    Thank you
     
    Last edited: Jul 7, 2022
  2. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    148
    You'd probably be better off using the fragmentation pipeline stage if your data is going to exceed the MTU (about 1400 bytes). Here's how you would configure a reliable and fragmented pipeline:

    Code (CSharp):
    1. var settings = new NetworkSettings();
    2. settings.WithFragmentationStageParameters(payloadCapacity: 10000);
    3.  
    4. var driver = NetworkDriver.Create(settings);
    5.  
    6. var pipeline = driver.CreatePipeline(typeof(FragmentationPipelineStage), typeof(ReliableSequencedPipelineStage));
    This will create a pipeline in which messages are first passed through the fragmentation stage (where they'll be broken up in smaller pieces that each fit inside a single packet), and then through the reliable stage (where each piece will be sent in a reliable manner).

    I wouldn't modify the baselib network interface parameters unless you have really specific needs.
     
    HernandoNJ likes this.
  3. CyFy

    CyFy

    Joined:
    Apr 4, 2019
    Posts:
    3
    Hi Simon,

    Thank you for your answer.
    I didn't realise you already answered me, before I updated my post. Not used to forums anymore.

    That works really well. So is it the correct behaviour, that the maximum payload I can send at once is somehow 32000 bytes?

    What would the baselib parameters do anyway? It didn't seem to have any effect for me.
     
  4. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    148
    The maximum payload that you can send through a fragmented and reliable pipeline is around 44KB. The reason for that is that there can only be a maximum of 32 reliable packets in flight (per pipeline and per connection). And each packet can only be ~1400 bytes in size, which results in a total maximum payload of ~44KB.

    I understand that for some applications this is an unfortunate limitation. We have plans to eventually remove it (or at least increase the limit), but I don't know when we'll get to that.

    If you wish to send reliable messages larger than the limit, you could implement your own fragmentation and queue up unsent traffic locally. This is what we do in Netcode for GameObjects. Messages are tagged with their length and added to a queue. We then send as much data from the queue as we can (keeping any remaining data in the queue to be sent later). On the receiving side we keep data queued up until we have entire messages. Note that such a strategy will induce quite a bit of latency for very large payloads, since sending a single message will require multiple roundtrips on the network.

    The maximum payload size parameter didn't work for you because the reliable pipeline stage already imposes its own (non-configurable) limit on the size of reliable packets, which supersedes the limit configured in the baselib parameters. If you were to send unreliable packets, then the baselib limit would have applied. (Note that in this case fragmentation would still occur, but at the IP layer, which is not something I recommend relying on.)

    I agree that all of this is poorly documented. This is something we wish to improve soon.
     
  5. CyFy

    CyFy

    Joined:
    Apr 4, 2019
    Posts:
    3
    That is what I also thougth would be the case, however I only managed to send a string with a size of 32000 which if I am not wrong would translate to 32000 bytes. I could of course miss something under the hood.

    Anyway, while looking for solutions, I stumbled upon LiteNetLib, which I will probably switch to for now, since I have sadly limited time, as this is part of my bachelor thesis.

    I have to say though, I am really impressed by the ease of use of Unity Transport. I love how little boilerplate it requires for delivering the level of control that it does. I am looking forward to using it again in the future. And thanks a lot for your help and insight.
     
    simon-lemay-unity likes this.
unityunity