日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Unity/DotNetty中集成Lidgren实现可靠UDP

發布時間:2023/12/4 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Unity/DotNetty中集成Lidgren实现可靠UDP 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

lidgren有幾個優點:

  • 分channel,每個channel都有單獨的消息隊列,不互相影響。

  • 每個消息可以單獨選擇使用可靠/不可靠傳輸。

  • 支持內網穿透

  • 自帶加密算法。

  • ?

    前端Unity:

    先貼一張前端使用的網絡框架圖:

    ?

    Lidgren的Github地址:https://github.com/lidgren/lidgren-network-gen3

    在Player Setting中,要加上宏定義UNITY

    連接:

    NetPeerConfiguration config = new NetPeerConfiguration (NetworkConfig.CONNECTION_IDENTIFIER);//參數是一個字符串標識,前后端一致。

    config.EnableMessageType (NetIncomingMessageType.ConnectionLatencyUpdated);//監聽收發心跳的事件。

    m_connection = new NetClient (config);

    m_connection.Start ();

    m_receiveCallBack = new SendOrPostCallback (OnReceiveMessage);//收發消息的回調

    m_connection.RegisterReceivedCallback(m_receiveCallBack, new SynchronizationContext());?

    m_connection.Connect (ip, port);

    ?斷開連接:

    m_connection.Disconnect (""); m_connection.UnregisterReceivedCallback (m_receiveCallBack);

    ?

    發送消息:

    NetOutgoingMessage nm = connection.CreateMessage (bytesLength); nm.Write (bytes, 0, bytesLength); m_connection.SendMessage (nm, (NetDeliveryMethod)channelType, channel);

    ?

    NetDeliveryMethod有以下幾類:

    UnReliable不可靠傳輸,順序和丟包都不能保證
    UnReliableSequence不可靠傳輸,按順序接收, 舊包直接丟棄
    ReliableUnOrdered可靠傳輸,不保證順序,但是不會丟包
    ReliableSequence可靠傳輸,和UnReliableSequence,但是有一個緩沖窗口,超過緩沖范圍的包會丟棄
    ReliableOrdered可靠傳輸,不丟包,保證順序

    ?接收消息:

    void OnReceiveMessage(object state)

    ? ? ? ? {

    ? ? ? ? ? ? NetIncomingMessage im;

    ? ? ? ? ? ? while ((im = m_connection.ReadMessage()) != null)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? switch (im.MessageType)

    ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.ErrorMessage:

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.WarningMessage:

              //處理錯誤和警告

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.DebugMessage:

              //debug輸出? ? ? ? ? ??

    ? ? ?         break;

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.VerboseDebugMessage:

              //消息重發或丟棄的debug消息

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.StatusChanged:

              //網絡狀態變化

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.Data:

    ? ? ? ? ? ? ? ? ?//收到消息處理,ReceiveMessages (im.ReadBytes (im.LengthBytes), im.LengthBytes);

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? case NetIncomingMessageType.ConnectionLatencyUpdated:

              //Lidgren收發心跳包后回調

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? default:

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? connection.Recycle(im);

    ? ? ? ? ? ? }

    ? ? ? ? }

    后端DotNetty:

    后端是參照TCPServerSocketChannel和TCPSocketChannel改的。

    Server的UnSafe可以寫一個空類:

    class LidgrenUdpServerUnsafeChannel : AbstractUnsafe

    ? ? ? ? {


    ? ? ? ? ? ? public LidgrenUdpServerUnsafeChannel(AbstractChannel channel) : base(channel)

    ? ? ? ? ? ? {


    ? ? ? ? ? ? }


    ? ? ? ? ? ? public override Task ConnectAsync(EndPoint remoteAddress, EndPoint localAddress)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? return null;

    ? ? ? ? ? ? }


    ? ? ? ? ? ? public void FinishRead()

    ? ? ? ? ? ? {

    ? ? ? ? ? ? }

    ? ? ? ? }

    再實現一個ServerChannel:

    public class LidgrenUdpServerChannel : AbstractChannel, IServerChannel

    ? ? {

    ? ? ? ? public const string CONNECTION_IDENTIFIER = "xxxxx";

    ? ? ? ? NetServer m_server;

    ? ? ? ? LidgrenChannelConfig m_config;


    ? ? ? ? public NetServer Server

    ? ? ? ? {

    ? ? ? ? ? ? get { return m_server; }

    ? ? ? ? }

    ? ? ? ? Dictionary<NetConnection, LidgrenUdpChannel> m_connectionList = new Dictionary<NetConnection, LidgrenUdpChannel>();

    ? ? ? ? public LidgrenUdpServerChannel()

    ? ? ? ? ? ? : base(null)

    ? ? ? ? {

    ? ? ? ? ? ? m_config = new LidgrenChannelConfig(CONNECTION_IDENTIFIER);

    ? ? ? ? ? ? m_server = new NetServer(m_config.Config);

    ? ? ? ? }

    ? ? ? ? protected override IChannelUnsafe NewUnsafe()

    ? ? ? ? {

    ? ? ? ? ? ? return new LidgrenUdpServerUnsafeChannel(this);

    ? ? ? ? }

    ? ? ...

    ? ? }

    開始監聽:


    protected override void DoBind(EndPoint localAddress)

    ? ? ? ? {

    ? ? ? ? ? ? m_config.Config.Port = ((IPEndPoint)localAddress).Port;

    ? ? ? ? ? ? this.m_server.Start();

    ? ? ? ? ? ? this.m_server.RegisterReceivedCallback(new System.Threading.SendOrPostCallback(OnRead), new System.Threading.SynchronizationContext());


    ? ? ? ? }

    ?OnRead類似客戶端的OnReceiveMessage:

    建立/斷開連接:

    case NetIncomingMessageType.StatusChanged:

    ? ? ? ? ? ? ? ? ? ? ? ? NetConnectionStatus ns = (NetConnectionStatus)im.ReadByte();

    ? ? ? ? ? ? ? ? ? ? ? ? if (ns == NetConnectionStatus.Connected)

    ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? LidgrenUdpChannel udpChannel = new LidgrenUdpChannel(this, im.SenderConnection);

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? Pipeline.FireChannelRead(udpChannel);

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? lock (((System.Collections.ICollection)m_connectionList).SyncRoot)

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? m_connectionList.Add(im.SenderConnection, udpChannel);

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? ? ? if (ns == NetConnectionStatus.Disconnected)

    ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? lock (((System.Collections.ICollection)m_connectionList).SyncRoot)

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? LidgrenUdpChannel channel = null;

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (m_connectionList.TryGetValue(im.SenderConnection, out channel))

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? channel.Pipeline.FireChannelInactive();

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? m_connectionList.Remove(im.SenderConnection);

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? ? ? }

                  break;

    接收消息:

    case NetIncomingMessageType.Data:

    ? ? ? ? ? ? ? ? ? ? ? ? LidgrenUdpChannel readChannel = null;

    ? ? ? ? ? ? ? ? ? ? ? ? lock (((System.Collections.ICollection)m_connectionList).SyncRoot)

    ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (m_connectionList.TryGetValue(im.SenderConnection, out readChannel))

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? readChannel.ReadBytes(im.ReadBytes(im.LengthBytes));

    ? ? ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ?   break;

    對于每一個客戶端,都有一個單獨的channel:

    public class LidgrenUdpChannel : AbstractChannel

    發送消息:

    protected int DoWriteBytes(IByteBuffer buf)

    ? ? ? ? {

    ? ? ? ? ? ? if (!buf.HasArray)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? throw new NotImplementedException("Only IByteBuffer implementations backed by array are supported.");

    ? ? ? ? ? ? }

    ? ? ? ? ? ? int sent = buf.ReadableBytes;

    ? ? ? ? ? ? NetOutgoingMessage msg = m_parentChannel.Server.CreateMessage();

    ? ? ? ? ? ? msg.Write(buf.Array, buf.ArrayOffset + buf.ReaderIndex, buf.ReadableBytes);

    ? ? ? ? ? ? m_connection.SendMessage(msg, NetDeliveryMethod.ReliableOrdered, 0);


    ? ? ? ? ? ? if (sent > 0)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? buf.SetReaderIndex(buf.ReaderIndex + sent);

    ? ? ? ? ? ? }


    ? ? ? ? ? ? return sent;

    ? ? ? ? }

    ? ? ? ? protected override void DoWrite(ChannelOutboundBuffer input)

    ? ? ? ? {

    ? ? ? ? ? ? while (true)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? object msg = input.Current;

    ? ? ? ? ? ? ? ? if (msg == null)

    ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? // Wrote all messages.

    ? ? ? ? ? ? ? ? ? ? break;

    ? ? ? ? ? ? ? ? }


    ? ? ? ? ? ? ? ? if (msg is IByteBuffer)

    ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? IByteBuffer buf = (IByteBuffer)msg;

    ? ? ? ? ? ? ? ? ? ? int readableBytes = buf.ReadableBytes;

    ? ? ? ? ? ? ? ? ? ? if (readableBytes == 0)

    ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? input.Remove();

    ? ? ? ? ? ? ? ? ? ? ? ? continue;

    ? ? ? ? ? ? ? ? ? ? }


    ? ? ? ? ? ? ? ? ? ? bool done = false;

    ? ? ? ? ? ? ? ? ? ? long flushedAmount = 0;


    ? ? ? ? ? ? ? ? ? ? int localFlushedAmount = this.DoWriteBytes(buf);

    ? ? ? ? ? ? ? ? ? ? flushedAmount += localFlushedAmount;

    ? ? ? ? ? ? ? ? ? ? if (!buf.IsReadable())

    ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? done = true;

    ? ? ? ? ? ? ? ? ? ? }


    ? ? ? ? ? ? ? ? ? ? input.Progress(flushedAmount);

    ? ? ? ? ? ? ? ? ? ? buf.Release();

    ? ? ? ? ? ? ? ? ? ? if (done)

    ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? input.Remove();

    ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? ? ? else

    ? ? ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? ? ? throw new InvalidOperationException();

    ? ? ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? ? ? else

    ? ? ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? ? ? // Should not reach here.

    ? ? ? ? ? ? ? ? ? ? throw new InvalidOperationException();

    ? ? ? ? ? ? ? ? }

    ? ? ? ? ? ? }

    ? ? ? ? }

    接收消息:

    ?

    public void ReadBytes(byte[] bytes){ ? ? ? ?
    ? ?
    if (!Open) ? ? ? ? ?
    ? ? ?
    return; ? ? ? ?
    ? ?
    this.EventLoop.Execute(()=> { ((LidgrenUdpUnsafe)Unsafe).ReadBytes(bytes); });}

    UnSafe中:

    public void FinishRead()

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? channel.Read();

    ? ? ? ? ? ? }


    ? ? ? ? ? ? public void ReadBytes(byte[] bytes)

    ? ? ? ? ? ? {

    ? ? ? ? ? ? ? ? IByteBufferAllocator allocator = channel.Allocator;

    ? ? ? ? ? ? ? ? IRecvByteBufAllocatorHandle allocHandle = RecvBufAllocHandle;


    ? ? ? ? ? ? ? ? IByteBuffer byteBuf = allocHandle.Allocate(allocator);

    ? ? ? ? ? ? ? ? byteBuf.WriteBytes(bytes);

    ? ? ? ? ? ? ? ? channel.Pipeline.FireChannelRead(byteBuf);

    ? ? ? ? ? ? ? ? channel.Pipeline.FireChannelReadComplete();

    ? ? ? ? ? ? ? ? allocHandle.ReadComplete();

    ? ? ? ? ? ? }

    Lidgren不支持ipv6,修改方法參照這里https://github.com/SteveProXNA/UnityLidgrenIPv6/tree/master/IPv6

    原文:http://www.cnblogs.com/drashnane/p/6415973.html


    .NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

    總結

    以上是生活随笔為你收集整理的Unity/DotNetty中集成Lidgren实现可靠UDP的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。