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. Dismiss Notice

Question UDP slow... how do you get real-time comm?

Discussion in 'Scripting' started by Ascanio1980, Oct 26, 2021.

  1. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    • I have two iOS devices on a local WiFi (dedicated high-end router, no other traffic, no internet).
    • Each device is running a native app compiled from Unity
    • Each app is using UdpClient.BeginReceive() and UdpClient.Send() to send each other short messages (such as "off", "on").
    • To visually test delay, I press a button onscreen to turn a big panel from black to white on the device's screen, and the other device does the same in reaction to incoming UDP messages.
    • I witness inconsistent lag times that go from null (probably less than 15ms) to something beyond 300ms.
    The two devices in question are iPad Pro 12.9" 5th generation, set to run at 120FPS. There is no question about performance. Graphics are not the issue (the panel on the device I am touching responds instantaneously to my touch).

    Code (CSharp):
    1. void Start()
    2.         {
    3.             try
    4.             {
    5.                 senderEndPoint = new IPEndPoint(IPAddress.Any, 0); // Any sender is good
    6.                 receivingUdpClient = new UdpClient(RECEIVING_PORT);
    7.                 receivingUdpClient.BeginReceive(new AsyncCallback(HandleMessageReceived), null);
    8.             } catch(Exception e)
    9.             {
    10.                 //TODO
    11.             }
    12.         }
    13.  
    14. public void HandleMessageReceived(IAsyncResult result)
    15.         {
    16.             try
    17.             {
    18.                 receivedData = receivingUdpClient.EndReceive(result, ref senderEndPoint);
    19.                 receivedString = Encoding.ASCII.GetString(receivedData);
    20.                 if (receivedString == "off")
    21.                 {
    22.                     SetPanelOff();
    23.                 }
    24.                 else if (receivedString == "on")
    25.                 {
    26.                     SetPanelOn();
    27.                 }
    28.                 receivingUdpClient.BeginReceive(new AsyncCallback(HandleMessageReceived), null);
    29.             }
    30.             catch(Exception e)
    31.             {
    32.                 //TODO
    33.             }
    34.         }
    I know I have a couple of other ways to deal with receiving messages, that I can try:
    1. Creating a separate thread and using UdpClient.Receive()
    2. Using await UdpClient.ReceiveAsync();
    3. Checking for data received in the Update look, using UdpClient.Receive()
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    How are you reaching the listening device from the sending device? What IP address are you using? Are you using your device's local IP address within your local network, or are you routing the datagrams through the public internet and listening via port forwarding or some other NAT scheme? Is this being done over wifi?
     
  3. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    The Router is not connected to the internet, devices have static IP addresses, messages are being sent directly from one device to another with specific IP on port 65500.
     
  4. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Have you tried a classic
    ping
    between two devices on this network? What kind of latency do you get?
     
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    I'd use the same code to ping between two laptops connected to the same wireless router, to determine whether the issue is device related or code related.

    Note I haven't seen that kind of latency locally with udp, but I always put the udp send/receive on their own threads, I haven't tested with iDevices, and I always do initial performance testing on wired networks to avoid transient issues such as interference from neighboring routers or something turning on an old microwave oven.
     
  6. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    OK this is interesting, I see the following:

    iPhone 12 Pro pings to iPad Pro 5th gen - between 3ms and 423ms, most of the time around 150ms
    iPad Pro 5th gen pings to iPhone 12 Pro - between 3ms and 814ms, most of the time around 45ms

    What could be the culprit? I am running off of a Netgear Wifi 6 AX1800 router.
     
  7. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    If I start pinging more and more (I accumulate the number of ping coroutines every time I press a button), things improve.

    Having about 5-10 pings per second running from each device, brings the ping time down to 3-60ms with most of results in the 25-30 range on both sides
     
  8. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Updated the firmware of the router, and nothing changed.
    If I get 10-15 pings per second on both sides, I see lags spiking every second or two, all the way to the 1xx figures (and more than that if I don't make the band busy at all).

    Having devices constantly ping each other isn't an issue, and I don't need a lot of bandwidth, but I do see packets being lost once I get a lot of pings going around and I try to get the two apps to actually pass messages.
     
  9. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    Personally I'm not a fan of the BeginReceive architecture. To me starting a seperate thread and using synchron Receive calls is easier to understand and you have more control over the whole process and resources.

    Anyways, from your code it's not really clear how you actually synchronise your receiving thread with Unity's main thread. What exactly happens inside your SetPanelOff / SetPanelOn methods?

    Over here I created a very simple example using a TCP connection to stream images from a background application. Of course, in this example the server and client are running on the same machine and therefore you don't have any visual delay. Even with this crude implementation I could crank up the send rate to about 10 images per second without any issues.

    I did not use UDP much for several reasons. The main reason is the relatively small packet size. Also most of my applications need a reliable information transfer. Though inside a LAN even UDP usually don't has any packet loss. Of course wireless connections are more vulnerable. However the receiving shouldn't be that slow. Have you tried including a running id inside your packet to see if packets are actually lost?
     
  10. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Bunny I’ll reply in points (and thanks for chiming in):

    - I was thinking the BeginReceive might be the culprit but I guess I found a bigger evil to fight ATM.

    - SetPanelOff is basically running gameObject.SetActive(false) on an object on stage.

    - I will look at your TCP example when I am at a computer. But given that UDP/ping are having latency issues, I doubt TCP will fix anything if not the loss of packets, which I can live with… mostly. Let’s say real-time is a must, reliability is a nice to have.
     
  11. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,524
    But the receive callback of BeginReceive is usually executed on a seperate thread. You can not use SetActive from any other thread than the main thread. So you want / need some sort of thread safe queue or transfer variable between your receiving thread and Unity's main thread and do the actual setting in Update.
     
  12. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Uhmmm… OK.
    Sorry but that’s still gibberish to me.

    I though an AsyncCallback would do the trick, and it appeared to do it. Abstracting me from all the multi thread logic.
     
  13. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Are you sure your instances of high latency aren't actually dropped packets?
     
  14. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Actually this is a good point. With UDP there is no built in retry. So you might tap the button on one device, not get a response, then tap it again in frustration and finally get a response. If you count latency from the "initial" tap, it might seem very high, but maybe it's just that the initial tap was lost and the second or third or so on actually made it to the destination.
     
  15. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Good point but it’s easy to spot a missed packet: you just don’t see a reaction from the other device (which will happen within .4 seconds at the most).

    latency I am measuring with pings
     
  16. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Are these pings you're doing with similar code to what you've posted, or with the ping utility? If you're seeing the latency issue with say the ping command, then you've eliminated your code as the culprit. If that's the case I'd investigate whether you're getting wifi interference from a neighbor's router or some other device using a similar frequency. People who live in apartments or other living situations where you live in close proximity to other people often run into this issue. I've also personally seen microwave ovens cause interference with wifi in the 2.4ghz spectrum, so if your devices can do 5ghz I'd give that a try since it is generally less congested.

    I once had a microwave oven where every time I cooked anything all my wifi devices would lose connection it was so bad. This was a long time ago back when I was using 802.11b, but it is the same frequency range as used today.
     
  17. Ascanio1980

    Ascanio1980

    Joined:
    Jun 7, 2019
    Posts:
    51
    Yep I am already there.
    My only other concern would be related to the SW layers underneath Unity’s app in iOS but I can’t imagine them being the culprit.

    I have been updating the router firmware and switching from 2.4 to 5Ghz, and trying different frequencies. No major difference.

    only other solution would be to go wired, trying to understand if USB-C Ethernet adapters with power delivery will work on the iPad Pros.
    That should eliminate the issue entirely