Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Pipeline silently dropping messages when window gains focus.

Discussion in 'Unity Transport' started by mbalmaceda, Nov 22, 2022.

  1. mbalmaceda

    mbalmaceda

    Joined:
    Sep 3, 2019
    Posts:
    2
    Hi. I have a really simple setup using the ReliableSequencedPipelineStage (2.0.0-pre.2, Unity 2022.2.0b8) where messages are being dropped without any kind of console message (I am aware of the 32 limit but it is no showing up in console, I am not sure if it is the same problem).

    The server code sends a uint for every frame and client prints an error for every number missing.

    To reproduce:
    - in two different unity editors add the "Menu" script to some game object and play
    - in one editor click "Start server"
    - in a second editor click "Start client"
    - in the first editor click "Start simulation"
    Server will start to send numers to the client, server and client will log those numbers.
    - click the second editor
    When second editor gains focus, after a mini halt, some messages will be skipped and the missing numbers will be logged as errors.

    Code (CSharp):
    1. using Unity.Networking.Transport;
    2. using UnityEngine;
    3.  
    4. public class Menu : MonoBehaviour
    5. {
    6.     private Server server;
    7.     private Client client;
    8.  
    9.     private bool serverRunning;
    10.     private bool clientRunning;
    11.  
    12.     private void OnGUI()
    13.     {
    14.         if (!serverRunning && !clientRunning && GUILayout.Button("Start server"))
    15.         {
    16.             server = new Server();
    17.             var endpoint = NetworkEndpoint.AnyIpv4;
    18.             endpoint.Port = 9000;
    19.             server.Initialize(endpoint);
    20.             serverRunning = true;
    21.         }
    22.        
    23.         if (!serverRunning && !clientRunning && GUILayout.Button("Start client"))
    24.         {
    25.             client = new Client();
    26.             client.Initialize(NetworkEndpoint.Parse("127.0.0.1", 9000));
    27.             clientRunning = true;
    28.         }
    29.  
    30.         if (serverRunning && GUILayout.Button("Start simulation"))
    31.         {
    32.             server.sendTest = true;
    33.         }
    34.     }
    35.    
    36.     void Update()
    37.     {
    38.         if(serverRunning) server.Update();
    39.         if(clientRunning) client.Update();
    40.     }
    41. }
    42.  
    Code (CSharp):
    1. using System;
    2. using Unity.Collections;
    3. using Unity.Networking.Transport;
    4. using UnityEngine;
    5.  
    6. public struct Server : IDisposable
    7. {
    8.     private NetworkDriver driver;
    9.     private NetworkPipeline pipeline;
    10.     private NativeList<NetworkConnection> connections;
    11.        
    12.     public bool sendTest;
    13.     private uint acc;
    14.  
    15.     public void Initialize(NetworkEndpoint endpoint)
    16.     {
    17.         Debug.Log($"SERVER: Initializing at " + endpoint.ToString());
    18.            
    19.         var settings = new NetworkSettings();
    20.         settings.WithNetworkConfigParameters(disconnectTimeoutMS: 3600000);
    21.         driver = NetworkDriver.Create(settings);
    22.         pipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
    23.        
    24.         if (driver.Bind(endpoint) != 0)
    25.             Debug.Log($"SERVER: Failed to bind to port {endpoint.Port}");
    26.         else
    27.             driver.Listen();
    28.  
    29.         connections = new NativeList<NetworkConnection>(16, Allocator.Persistent);
    30.     }
    31.  
    32.     public void Dispose()
    33.     {
    34.         driver.Dispose();
    35.         connections.Dispose();
    36.     }
    37.  
    38.     public void Update()
    39.     {
    40.         driver.ScheduleUpdate().Complete();
    41.  
    42.         // CleanUpConnections
    43.         for (int i = connections.Length - 1; i >= 0; i--)
    44.         {
    45.             if (!connections[i].IsCreated)
    46.             {
    47.                 connections.RemoveAt(i);
    48.             }
    49.         }
    50.  
    51.         // AcceptNewConnections
    52.         NetworkConnection newConnection;
    53.         while ((newConnection = driver.Accept()) != default)
    54.         {
    55.             connections.Add(newConnection);
    56.             Debug.Log($"SERVER: Accepted a connection: clientIndex = {connections.Length - 1}");
    57.         }
    58.  
    59.         // Handle messages
    60.         for (int clientIndex = 0; clientIndex < connections.Length; clientIndex++)
    61.         {
    62.             var connection = connections[clientIndex];
    63.             NetworkEvent.Type cmd;
    64.             while ((cmd = driver.PopEventForConnection(connection, out var reader)) != NetworkEvent.Type.Empty)
    65.             {
    66.                 if (cmd == NetworkEvent.Type.Data)
    67.                 {
    68.                        
    69.                 }
    70.                 else if (cmd == NetworkEvent.Type.Disconnect)
    71.                 {
    72.                     Debug.Log($"SERVER: Client disconnected from server: clientIndex = {clientIndex}");
    73.                     connections[clientIndex] = default(NetworkConnection);
    74.                 }
    75.             }
    76.         }
    77.  
    78.         if (sendTest)
    79.         {
    80.             acc++;
    81.                
    82.             Debug.Log($"Sending {acc}");
    83.                
    84.             for (int i = 0; i < connections.Length; i++)
    85.             {
    86.                 var connection = connections[i];
    87.  
    88.                 driver.BeginSend(pipeline, connection, out var writer);
    89.                 writer.WriteUInt(acc);
    90.                 driver.EndSend(writer);
    91.             }
    92.         }
    93.     }
    94. }
    Code (CSharp):
    1. using System;
    2. using Unity.Networking.Transport;
    3. using UnityEngine;
    4.  
    5. public struct Client : IDisposable
    6. {
    7.     public NetworkDriver driver;
    8.     public NetworkPipeline pipeline;
    9.     public NetworkConnection connection;
    10.  
    11.     public uint acc;
    12.  
    13.     public void Initialize(NetworkEndpoint endPoint)
    14.     {
    15.         Debug.Log($"CLIENT: Connecting to server in {endPoint.ToString()}");
    16.  
    17.         var settings = new NetworkSettings();
    18.         settings.WithNetworkConfigParameters(disconnectTimeoutMS: 3600000);
    19.         driver = NetworkDriver.Create(settings);
    20.         pipeline = driver.CreatePipeline(typeof(ReliableSequencedPipelineStage));
    21.         connection = driver.Connect(endPoint);
    22.     }
    23.  
    24.     public void Dispose()
    25.     {
    26.         driver.Dispose();
    27.     }
    28.        
    29.     public void Update()
    30.     {
    31.         driver.ScheduleUpdate().Complete();
    32.  
    33.         if (!connection.IsCreated)
    34.         {
    35.             Debug.Log("CLIENT: Connection failed");
    36.             return;
    37.         }
    38.  
    39.         var cmd = default(NetworkEvent.Type);
    40.         while ((cmd = connection.PopEvent(driver, out var reader)) != default)
    41.         {
    42.             switch (cmd)
    43.             {
    44.                 case NetworkEvent.Type.Connect:
    45.                 {
    46.                     Debug.Log("CLIENT: Connected to server");
    47.                     break;
    48.                 }
    49.                 case NetworkEvent.Type.Data:
    50.                 {
    51.                     var serverAcc = reader.ReadUInt();
    52.  
    53.                     while (serverAcc > acc + 1)
    54.                     {
    55.                         Debug.LogError($"Missing {++acc}");
    56.                     }
    57.  
    58.                     Debug.Log($"Receiving {serverAcc}");
    59.                     acc = serverAcc;
    60.  
    61.                     break;
    62.                 }
    63.                 case NetworkEvent.Type.Disconnect:
    64.                 {
    65.                     Debug.Log("CLIENT: Disconnected from server");
    66.                     connection = default(NetworkConnection);
    67.                     break;
    68.                 }
    69.                 default: throw new Exception();
    70.             }
    71.         }
    72.     }
    73. }
     
  2. simon-lemay-unity

    simon-lemay-unity

    Unity Technologies

    Joined:
    Jul 19, 2021
    Posts:
    429
    It is likely that you are hitting the limit of 32 in-flight messages if you are sending a reliable message every frame. This is signaled through return codes, but the example code above doesn't handle those so the errors appear to be silent.

    In this case, I'd guess
    EndSend
    is failing with return code
    Error.StatusCode.NetworkSendQueueFull
    (value -5). This indicates that the reliable window is full (i.e. the maximum number of packets in flight has been reached). Note that
    BeginSend
    can also fail in a similar manner. Please refer to the FAQ for how to deal with this error. The section of the documentation on the reliable pipeline might also be useful.