Search Unity

Showcase LiteNetLib - another reliable udp library.

Discussion in 'Multiplayer' started by RevenantX, Jun 30, 2016.

  1. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Hi!. I want to introduce my "Reliable UDP" network library.
    https://github.com/RevenantX/LiteNetLib

    Discord
    https://discord.gg/FATFPdy

    Documentation
    https://revenantx.github.io/LiteNetLib/index.html

    Features
      • Lightweight
        • Small CPU and RAM usage
        • Small packet size overhead ( 1 byte for unreliable, 3 bytes for reliable packets )
      • Simple connection handling
      • Peer to peer connections
      • Helper classes for sending and reading messages
      • Different send mechanics
        • Reliable with order
        • Reliable without order
        • Ordered but unreliable with duplication prevention
        • Simple UDP packets without order and reliability
      • Fast packet serializer
      • Automatic small packets merging
      • Automatic fragmentation of reliable packets
      • Automatic MTU detection
      • UDP NAT hole punching
      • NTP time requests
      • Packet loss and latency simulation
      • IPv6 support (dual mode)
      • Connection statisitcs (need DEBUG or STATS_ENABLED flag)
      • Multicasting (for discovering hosts in local network)
      • Unity support
      • Supported platforms:
        • Windows/Mac/Linux (.NET Framework, Mono, .NET Core)
        • Android (Unity)
        • iOS (Unity)
        • UWP Windows 10 including phones
        • Lumin OS (Magic Leap)
    It used in some game projects already. And works very stable and fast.
    You can use it without Unity3d (just Mono or .NET) that sometimes very useful for servers. It doesn't use LINQ or Reflection (except in NetSerializer). And doesn't use native code.
     
    Last edited: Dec 10, 2019
  2. Zoey_O

    Zoey_O

    Joined:
    Mar 15, 2013
    Posts:
    28
    I like how simple this looks. I've used a number of other libraries (including lidgren multiple times) in Unity, but my choices are limited this time since this project needs to have no paid assets in it. I was going to go with Lidgren again, but I'll give this a shot first.
     
    ivan866 likes this.
  3. ManHunterITA

    ManHunterITA

    Joined:
    Sep 3, 2013
    Posts:
    341
    Can you provide any comparison/benchmark with Lidgren Network? It can be very interesting to compare them.
    I will give it a shot if it results more stable and fast than Lidgren lib!
     
    forestrf and AgentFire like this.
  4. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    I created this library for my FPS multiplayer game because lidgren-network have bugs in Reliable channel (drop packets and reordering)
    About performance: In last update i improved and tested transfer speed. Result - 100 mbytes per second on local socket with ReliableInOrder packets.
     
  5. dmennenoh

    dmennenoh

    Joined:
    Jul 1, 2015
    Posts:
    379
    >>NTP Time Requests

    Do you possibly have an example of this?
     
  6. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
  7. dmennenoh

    dmennenoh

    Joined:
    Jul 1, 2015
    Posts:
    379
    Hey, thanks! That works, but is this SNTP? Trying to get several clients to tightly sync.
     
  8. dmennenoh

    dmennenoh

    Joined:
    Jul 1, 2015
    Posts:
    379
    Oops - nevermind. I see from the NtpSyncModule class that it is true NTP.

    Thank you.
     
  9. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Yes. It not so accurate.
     
  10. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    From RFC :)
    An SNTP client implementing the on-wire protocol has a single server
    and no dependent clients. It can operate with any subset of the NTP
    on-wire protocol, the simplest approach using only the transmit
    timestamp of the server packet and ignoring all other fields.
    However, the additional complexity to implement the full on-wire
    protocol is minimal so that a full implementation is encouraged.

    That exactly what i do. Only timestamp is used. But it works with any servers)
     
  11. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    siliwangi likes this.
  12. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    August-September updates.
    • Connection statisitcs (received/sent packets/bytes count)
    • Multicasting (for discovering servers in local network)
    • Better latency simulation (you can set MinLatency)
    • Better information about disconnects (string replaced to informative Enum)
    • And as always - optimizations :)
    These features in master branch.
     
    Last edited: Sep 6, 2016
  13. Sir_WaLeK

    Sir_WaLeK

    Joined:
    Jan 24, 2014
    Posts:
    3
    Hey can we get some documentation ? And maybe some more examples ?
     
  14. Dennis59

    Dennis59

    Joined:
    Jan 8, 2013
    Posts:
    66
    RevenantX, I am attempting to use LiteNetLib to communicate between a server built in Unity and a stand alone server written in C#. I've been able to communicate between two Unity instances using LiteNetLib but cannot get a Unity instance to connect to a stand alone LiteNetLib server. Using the code shown below on the server the only response in the console dialog is "Database Server status true port 5000". It appears that there is no data being received from the Unity client. I've tried disabling firewalls etc without improvement. The same client that I'm using connects to another Unity instance just fine. Any suggestions would be greatly appreciated.

    Code (csharp):
    1.  
    2. using System;
    3. using System.Threading;
    4. using LiteNetLib;
    5. using LiteNetLib.Utils;
    6.  
    7. class Program
    8. {
    9.     static void Main(string[] args)
    10.     {
    11.         int port = 5000;
    12.        TestNet tn;
    13.  
    14.         EventBasedNetListener listener = new EventBasedNetListener();
    15.         NetServer server = new NetServer(listener, 10, "LNDB Server");
    16.         bool serverStat = server.Start(port);
    17.  
    18.         server.DiscoveryEnabled = true;
    19.         server.UnconnectedMessagesEnabled = true;
    20.        
    21.         tn = new TestNet(server);
    22.  
    23.         Console.WriteLine("Database Server  status" + serverStat + " port " + port);
    24.  
    25.         listener.PeerConnectedEvent += peer =>
    26.         {
    27.             Console.WriteLine("We got connection: {0}", peer.EndPoint); // Show peer ip
    28.             NetDataWriter writer = new NetDataWriter();                 // Create writer class
    29.             writer.Put(1);                                              // Put some string
    30.             peer.Send(writer, SendOptions.ReliableOrdered);             // Send with reliability
    31.  
    32.             listener.NetworkReceiveEvent += tn.OnServerReceive;        // Connect the OnNetworkReceive callback
    33.         };
    34.  
    35.         listener.NetworkReceiveUnconnectedEvent += tn.OnNetworkReceiveUnconnected;
    36.  
    37.         tn.Poller();
    38.     }
    39. }
    40.  
    41. class TestNet
    42. {
    43.     private NetServer _netServer;
    44.  
    45.     public TestNet(NetServer ns)
    46.     {
    47.         _netServer = ns;
    48.     }
    49.  
    50.     public void Poller()
    51.     {
    52.         while (true)
    53.         {
    54.             _netServer.PollEvents();
    55.             Thread.Sleep(15);
    56.         }
    57.     }
    58.     public void OnServerReceive(NetPeer peer, NetDataReader reader)
    59.     {
    60.         Console.WriteLine("[SERVER] Received data");
    61.     }
    62.  
    63.     public void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType)
    64.     {
    65.         Console.WriteLine("[SERVER] Received discovery request");
    66.  
    67.         if (messageType == UnconnectedMessageType.DiscoveryRequest)
    68.         {
    69.             _netServer.SendDiscoveryResponse(new byte[] { 1 }, remoteEndPoint);
    70.         }
    71.     }
    72.  
    73. }
    74.  
     
  15. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Hi!. Can you show client connection code? Are you using the same "ConnectionKey" - "LNDB Server"?
     
    Last edited: Nov 13, 2016
  16. Dennis59

    Dennis59

    Joined:
    Jan 8, 2013
    Posts:
    66
    Yes, same ConnectionKey. Code from Client:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using LiteNetLib;
    4. using LiteNetLib.Utils;
    5.  
    6. public class GameClient : MonoBehaviour, INetEventListener
    7. {
    8.     private NetClient _netClient;
    9.  
    10.     void Start ()
    11.     {
    12.         _netClient = new NetClient(this, "LNDB Server");
    13.         _netClient.Start();
    14.         _netClient.UpdateTime = 15;
    15.     }
    16.  
    17.     void Update ()
    18.     {
    19.        _netClient.PollEvents();
    20.  
    21.         if (_netClient.IsConnected)
    22.         {
    23.             Debug.Log("Client is connected!");
    24.         }
    25.         else
    26.         {
    27.             Debug.Log("Sending discovery packet to endpoint");
    28.             _netClient.SendDiscoveryRequest(new byte[] { 1 }, 5000);
    29.         }
    30.     }
    31.  
    32.     void OnDestroy()
    33.     {
    34.         if(_netClient != null)
    35.             _netClient.Stop();
    36.     }
    37.  
    38.     public void OnPeerConnected(NetPeer peer)
    39.     {
    40.         Debug.Log("[CLIENT] We connected to " + peer.EndPoint);
    41.     }
    42.  
    43.     public void OnPeerDisconnected(NetPeer peer, DisconnectReason reason, int socketErrorCode)
    44.     {
    45.         Debug.Log("[CLIENT] We disconnected because " + reason);
    46.     }
    47.  
    48.     public void OnNetworkError(NetEndPoint endPoint, int socketErrorCode)
    49.     {
    50.         Debug.Log("[CLIENT] We received error " + socketErrorCode);
    51.     }
    52.  
    53.     public void OnNetworkReceive(NetPeer peer, NetDataReader reader)
    54.     {
    55.  
    56.     }
    57.  
    58.     public void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType)
    59.     {
    60.         if (messageType == UnconnectedMessageType.DiscoveryResponse && _netClient.Peer == null)
    61.         {
    62.             Debug.Log("[CLIENT] Received discovery response. Connecting to: " + remoteEndPoint);
    63.             _netClient.Connect(remoteEndPoint);
    64.         }
    65.     }
    66.  
    67.     public void OnNetworkLatencyUpdate(NetPeer peer, int latency)
    68.     {
    69.        
    70.     }
    71. }
    72.  
     
  17. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Do you use same versions of LiteNetLib on client and server? (in repo UnityExample there is outdated lib, use from Release pages)
    P.S. And better set UpdateTime before Start() call
     
    ivan866 likes this.
  18. Dennis59

    Dennis59

    Joined:
    Jan 8, 2013
    Posts:
    66
    I want to say yes, should all be from tag 0.6.1, but I'll make sure all is the same. And I'll try UpdateTime as suggested.
     
  19. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Hm... Server instance in your local network?
    P.S. I just checked your code locally. It works.
     
  20. Dennis59

    Dennis59

    Joined:
    Jan 8, 2013
    Posts:
    66
    RevenantX, I copied over the dll from the stand alone and that worked. As I write this I realize that I didn't try the UpdateTime but will add that too. Thanks for suggesting to look at the library versions.

    Looks like a great library. Looking forward to working with it.
     
  21. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Thanks :)
     
  22. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Some news:
    • Added .NET Core support
    • Added small packets merging
    • 100 stars at github :)
     
  23. Apparaten_

    Apparaten_

    Joined:
    Jul 9, 2013
    Posts:
    45
    This looks great :)

    Can I use multiple netClients in the same context (app/game) and connect to different servers?
     
  24. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Sure you can! :) Sample project (LibSample) uses two or more clients for tests.
     
  25. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Master branch update:
    • Full PeerToPeer support
    • Additional data can be send with disconnect message
    • As always fixes and optimizations
     
    HiWill likes this.
  26. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    I'm going to have to check this out this weekend. I like how lean and clean its usage is. Thanks for your efforts!
     
  27. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
  28. jc_lvngstn

    jc_lvngstn

    Joined:
    Jul 19, 2006
    Posts:
    1,508
    Very nice.
    by the way...I love this:
    _netSerializer.Subscribe<SamplePacket>(OnSamplePacketReceived);

    Something I was wondering, for non-structs, could you implement something like an ILiteNetSerialized interface, with Serialize and Deserialize methods, passing in a serializer. For objects that implement that interface, their serialize methods would be responsible for their serialization. Sort of like:

    class MyCreature : ILiteNetSerialized
    {
    private float Damage;
    private int OwnerID;

    void Serialize(Serializer writer)
    {
    writer.Put(transform.position.x);
    ...
    writer.Put(Damage);
    writer.Put(OwnerID);
    }

    // The deserializer would perform the same patern, but in reverse obviously.
    }
    Calling serializer.Put(MyCreature) see it implements ILiteNetSerialized, and call the serializer for the creature. Or is this simply a violation of the single responsibility principle?
    Would this be of use, or even work well in LiteNetLib's situation?
     
    Last edited: Feb 15, 2017
  29. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    You can implement this feature with extension without NetSerializer;
    Code (CSharp):
    1. interface ILiteNetSerialized ...
    2.  
    3. public static void Serialize(this NetDataWriter writer, ILiteNetSerialized obj)
    4. {
    5.    obj.Serialize(writer);
    6. }
    And look at NetDataWriter at all)
     
    Last edited: Feb 18, 2017
  30. caracostea

    caracostea

    Joined:
    Feb 17, 2017
    Posts:
    3
    Hi,

    Can this library be used for massive data transfers over high latency-bandwidth product networks?
    Is it able to saturate the bandwidth of high latency links? (say 500ms)

    How does it cope with congestion? Is this addressed?
    I'm highly interested in moving from UDT, because I am currently using a mixed-mode c++ wrapper which limits me to windows platforms and I'm currently aiming for .Net Core.

    Thanks!
     
    Last edited: Feb 17, 2017
  31. JosephHK

    JosephHK

    Joined:
    Jan 28, 2015
    Posts:
    40
    As far as I know, it seems that udp may not work over 3g network. Did you test your library over 3g?

    Thanks
     
  32. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    I tested over 3g. And it works. Android mobile game (on Unity3d) uses this library for PVP multiplayer.
     
  33. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Hi! I didn't test this library in that circumstances.
    I tested high latency ( i have simulator ), and tested on bad mobile network. And all was fine.
    LiteNetLib have bandwith control.
    Code (CSharp):
    1.  public void AddFlowMode(int startRtt, int packetsPerSecond)
    But that mechanism not tested well. You can try. And if you found some bugs i will fix them :)
     
  34. caracostea

    caracostea

    Joined:
    Feb 17, 2017
    Posts:
    3
    Hey,

    Thanks for your reply!

    Apart from bandwidth control is there also a congestion control implemented?
     
  35. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    congestion depends on bandwith control. maybe i misunderstood you
     
  36. caracostea

    caracostea

    Joined:
    Feb 17, 2017
    Posts:
    3
    Well, not entirely...
    Congestion also depends on network conditions.
    And if the network happens to be the Internet... then the conditions change a lot.
    The protocol needs to be able to auto adjust the sending rate to cope with the way the dropped packets count and RTT varies.

    So I guess there's no such thing implemented so far...

    Have a look at TCP congestion control, just to get a better ideea.

    Cheers!
     
  37. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    I have flow control. That reduces send rate when RTT less than values that you add via "AddFlowMode" method.
     
  38. forestrf

    forestrf

    Joined:
    Aug 28, 2010
    Posts:
    230
    I am using Lidgren right now but I am on a point that I can change to other solutions.
    I am scared about some things of Lidgren, but how stable is yours? Nat punching and flow control are too good to be true and I really want to use this library, before Lidgren punches me with its lack of flow control.

    Thank you for this. I don't want to use the convoluted UNET if I can and I don't care about webgl

    Also, a latency simulator with bursts of packet loss for some milliseconds would be great as it is common in a lot of wifi networkos and more but it was not testable in Lidgren. I can try to implement it if you say that is is stable enough and it is not already done :D
     
    Last edited: Feb 27, 2017
  39. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    I am created this library because lidgren works unstable with Reliable packets (packet drops with deadlocks).
    LiteNetLib version 0.6.1 stable and used in some commercial games.
    About "Nat punching". Lidgren-network has NAT punching too. And my code based on lidgren method :)
    And if you find some bugs i will try fix them asap (library code is clean and simple :)). I think this is main advantage over lidgren now (Lidgren network is not supported accroding to github page)
     
    -chris, forestrf and HiWill like this.
  40. edoarn

    edoarn

    Joined:
    Feb 8, 2014
    Posts:
    10
    Hey RevenantX, I found your library really nice and simple to use, thank you!
    I just wanted to ask you about your implementation of the NAT punch module. I couldn't properly figure out how it works even after researching about it.
    As far as I understood, both clients first need to communicate with a master server through a public address, this server actually "punches" its way in and forwards the NAT info to those clients, so that they can connect directly.
    I'm not so sure I got it right, in any case, how did you do it?
     
    forestrf likes this.
  41. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Look at nat punch example at github. There client and server code in one file. But you can separate this classes.
     
  42. SiliconDroid

    SiliconDroid

    Joined:
    Feb 20, 2017
    Posts:
    302
    Nice lib @RevenantX! I've had 8 clients connected to a server for many hours without issue. Compiling C# to an .exe on windows and then running that very same .exe on a nix box with mono installed without issue is so sweet:cool:.
     
    Last edited: May 29, 2017
    RevenantX likes this.
  43. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Some news as always
    New pre-release available 0.7.3:
    New Features
    • Full P2P support
      • Merged NetServer and NetClient into one NetManager.
    • Additional data can be send with disconnect packet ( but packet is unreliable )
    • Added NetSerializer class for easy and fast packet serialization
    • Optional small packet merging
    • .NET Core support
    • More documentation in code ( and xml generated documentation )
    • Added support to read and write arrays in NetDataReader and NetDataWriter
    • Optimizations and fixes.
    0.7.1 changes
    • Fixed hostname resolving
    • Fixed crash in unity3d when .NET 2.0 target selected
    • Added optional "ReuseAddress" setting
    • Added tag object to NetPeer
    0.7.2 changes
    • Reduced generated garbage in most situations
    • Improved performance
    • Critical fixes ( regressions in 0.7 and 0.7.1 )
    • NetSerializer fixes and usability improvements
    • Added .net core binaries
    0.7.3 changes
    • Fixes in NetSerializer
    • Fix reliable resend
     
  44. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    755
    For this feature "Automatic fragmentation of reliable packets", does that mean it supports sending large amounts of data in one event? So we don't have to manage it ourselves for sending many different packets to get the full data.
     
  45. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Yes. But there some limitations. Maximum size of automaticly fragmented packet is 65535 * MTU. With mininum MTU - maximum data size will be around 32 mb. With MTU == 1500 - maximum data size will be 91 mb
     
    -chris likes this.
  46. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    755
    Alright thank you. Could you provide more info on NetworkReceiveUnconnected, and maybe an example on how to use it? From what I've been able to find it looks like its a way to get data from the server without connecting to it completely, which would be perfect for my use case. I'm looking to replace my master server backend from UNET to something a bit more reliable. Basically anytime I connect to the master server its just to send some data such as hey this server is still on, or to request data such as a players account id.
     
  47. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    Unconnected messages - unreliable in my library.
    Usage very simple. There is methods in NetManager (NetClient/NetServer in old version):
    Code (CSharp):
    1. public bool SendUnconnectedMessage(byte[] message, NetEndPoint remoteEndPoint)
    2. public bool SendUnconnectedMessage(NetDataWriter writer, NetEndPoint remoteEndPoint)
    3. public bool SendUnconnectedMessage(byte[] message, int start, int length, NetEndPoint remoteEndPoint)
    On the other side you will receive in your EventListener
    Code (CSharp):
    1. void OnNetworkReceiveUnconnected(NetEndPoint remoteEndPoint, NetDataReader reader, UnconnectedMessageType messageType);
     
  48. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    755
    Ah okay, since it's unreliable I'd probably want to go with connecting to the server then. Is there a limit to the number of connections the server can have at once? I think this is my last question. Thank you!
     
  49. RevenantX

    RevenantX

    Joined:
    Jul 17, 2012
    Posts:
    148
    This is controlled variable:
    Code (CSharp):
    1.  public NetManager(INetEventListener listener, int maxConnections, string connectKey)
     
  50. emrys90

    emrys90

    Joined:
    Oct 14, 2013
    Posts:
    755
    So there's no inherent limit and I can set that value to something really high like 10K?