LiteNetLib封装
LiteNetLib使用响应函数返回网络数据,但我不想在服务器程序中出现LiteNetLib相关的大量代码,就只有把LiteNetLib封装成了一个单独的类,然后暴露几种LiteNetLib服务器运行的消息队列。而我自己的逻辑服务器解耦LiteNetLib服务器,只需要拉取这几种消息即可。
封装LiteNetLib的架构好处如下:
我的服务器(LiteNetLib服务器) =====> LiteNetLib服务器-----我的服务器。
Form1
using LiteNetLib; using LiteNetLib.Utils; using MessagePack; using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel; namespace LiteNetServer { public partial class Form1 : Form { public LiteNetService NetService = new LiteNetService(); public Form1() { InitializeComponent(); if (NetService.server.IsRunning) MT.ps(listBox1, "Server starting... Port:" + NetService.server.LocalPort); Task.Run(Thread1); } //发对象 private void button2_Click(object sender, EventArgs e) { List<OBJ01> playerList = new(); for (int i = 0; i< 100000; i++) playerList.Add(new OBJ01 { id = 1, aaa = "哈哈哈哈", x = 100, y = 100 }); MT.SendListToClient(NetService.clients, int.Parse(textBox1.Text), MsgType.OBJ01, playerList); MT.ps(listBox1, "向客户端ID:" + textBox1.Text + " 发送对象player"); } private void button3_Click(object sender, EventArgs e) { List<OBJ02> items = new(); for (int i = 0; i< 10000; i++) items.Add(new OBJ02 { id = 1001, bbb = "物品1", z = 10 }); MT.SendListToClient(NetService.clients, int.Parse(textBox1.Text), MsgType.OBJ02, items); MT.ps(listBox1, "向客户端ID:" + textBox1.Text + " 发送对象item"); } void Thread1() { while (true) { Task.Delay(200).Wait(); // 连接请求 var reqs = NetService?.FetchAndClearConnectionRequests(); if (reqs.Count > 0) { foreach (var r in reqs) MT.ps(listBox1, $"收到连接请求 {r.RemoteEndPoint} 时间:{r.Timestamp:HH:mm:ss}"); } // 连接成功 var conns = NetService?.FetchAndClearPeerConnectedMessages(); if (conns.Count > 0) { foreach (var p in conns) MT.ps(listBox1, $"客户端已连接,ID:{p.Id} 时间:{p.Timestamp:HH:mm:ss}"); } // 连接断开 var disconns = NetService?.FetchAndClearPeerDisconnectedMessages(); if (disconns.Count > 0) { foreach (var d in disconns) MT.ps(listBox1, $"客户端断开,ID:{d.Id} 原因:{d.Reason} 时间:{d.Timestamp:HH:mm:ss}"); } // 收到消息 var recvs = NetService?.FetchAndClearObj01Lists(); if (recvs.Count>0) { List<OBJ01> usblist = recvs.First(); MT.ps(listBox1, $"收到客户端OBJ01:{recvs.Count}, usblist数量:{usblist.Count}"); } var recvs2 = NetService?.FetchAndClearObj02Lists(); if (recvs2.Count>0) { List<OBJ02> usblist = recvs2.First(); MT.ps(listBox1, $"收到客户端OBJ02:{recvs2.Count}, usblist数量:{usblist.Count}"); } } } } }LiteNetService
using LiteNetLib; using LiteNetLib.Utils; using MessagePack; using System; using System.Collections.Generic; using System.Collections.Concurrent; namespace LiteNetServer { public class LiteNetService : IDisposable { public static EventBasedNetListener listener = new EventBasedNetListener(); public NetManager server = new NetManager(listener); public Dictionary<int, NetPeer> clients = new(); // 事件消息队列(并行安全) public ConcurrentQueue<ConnectionRequestMsg> ConnectionRequests { get; } = new(); public ConcurrentQueue<PeerConnectedMsg> PeerConnectedMessages { get; } = new(); public ConcurrentQueue<PeerDisconnectedMsg> PeerDisconnectedMessages { get; } = new(); // 新增:接收到的 OBJ01 列表队列(并行安全) public ConcurrentQueue<List<OBJ01>> Obj01Messages { get; } = new(); public ConcurrentQueue<List<OBJ02>> Obj02Messages { get; } = new(); // 公开事件,保留但可不订阅 public event Action<ConnectionRequest> ConnectionRequestEvent; public event Action<NetPeer> PeerConnectedEvent; public event Action<NetPeer, DisconnectInfo> PeerDisconnectedEvent; public event Action<NetPeer, NetPacketReader, byte, DeliveryMethod> NetworkReceiveEvent; // Fetch 方法:从并发队列中取出并返回当前所有元素 public List<ConnectionRequestMsg> FetchAndClearConnectionRequests() { var list = new List<ConnectionRequestMsg>(); while (ConnectionRequests.TryDequeue(out var item)) list.Add(item); return list; } public List<PeerConnectedMsg> FetchAndClearPeerConnectedMessages() { var list = new List<PeerConnectedMsg>(); while (PeerConnectedMessages.TryDequeue(out var item)) list.Add(item); return list; } public List<PeerDisconnectedMsg> FetchAndClearPeerDisconnectedMessages() { var list = new List<PeerDisconnectedMsg>(); while (PeerDisconnectedMessages.TryDequeue(out var item)) list.Add(item); return list; } // 取出所有 OBJ01 消息(每个元素是一次从网络反序列化得到的 List<OBJ01>) public List<List<OBJ01>> FetchAndClearObj01Lists() { var list = new List<List<OBJ01>>(); while (Obj01Messages.TryDequeue(out var item)) list.Add(item); return list; } public List<List<OBJ02>> FetchAndClearObj02Lists() { var list = new List<List<OBJ02>>(); while (Obj02Messages.TryDequeue(out var item)) list.Add(item); return list; } // 构造函数:初始化监听器、服务器,并订阅事件 public LiteNetService() { listener.ConnectionRequestEvent += OnConnectionRequestHandler; listener.PeerConnectedEvent += OnPeerConnectedHandler; listener.PeerDisconnectedEvent += OnPeerDisconnectedHandler; listener.NetworkReceiveEvent += OnNetworkReceiveHandler; server.Start(1435); Task.Run(Thread2); } void Thread2() { while (true) { Task.Delay(200).Wait(); if (server == null) continue; server.PollEvents(); } } // 使用命名方法替代 lambda,便于理解 private void OnConnectionRequestHandler(ConnectionRequest request) { try { request.AcceptIfKey("KEY20260601"); ConnectionRequests.Enqueue(new ConnectionRequestMsg { RemoteEndPoint = request.RemoteEndPoint?.ToString(), Timestamp = DateTime.Now }); } catch { } ConnectionRequestEvent?.Invoke(request); } private void OnPeerConnectedHandler(NetPeer peer) { clients[peer.Id] = peer; PeerConnectedMessages.Enqueue(new PeerConnectedMsg { Id = peer.Id, EndPoint = peer.Id.ToString(), Timestamp = DateTime.Now }); PeerConnectedEvent?.Invoke(peer); } private void OnPeerDisconnectedHandler(NetPeer peer, DisconnectInfo info) { if (clients.ContainsKey(peer.Id)) clients.Remove(peer.Id); PeerDisconnectedMessages.Enqueue(new PeerDisconnectedMsg { Id = peer.Id, Reason = info.Reason.ToString(), Timestamp = DateTime.Now }); PeerDisconnectedEvent?.Invoke(peer, info); } private void OnNetworkReceiveHandler(NetPeer peer, NetPacketReader reader, byte channel, DeliveryMethod method) { MsgType type = (MsgType)reader.GetByte(); byte[] data = reader.GetRemainingBytes(); if (type == MsgType.OBJ01) { Obj01Messages.Enqueue(MessagePackSerializer.Deserialize<List<OBJ01>>(data)); } else if (type == MsgType.OBJ02) { Obj02Messages.Enqueue(MessagePackSerializer.Deserialize<List<OBJ02>>(data)); } reader.Recycle(); } public void Dispose() { server.Stop(); server = null; listener = null; clients.Clear(); } } // 事件消息对象 public class ConnectionRequestMsg { public string RemoteEndPoint { get; set; } public DateTime Timestamp { get; set; } } public class PeerConnectedMsg { public int Id { get; set; } public string EndPoint { get; set; } public DateTime Timestamp { get; set; } } public class PeerDisconnectedMsg { public int Id { get; set; } public string Reason { get; set; } public DateTime Timestamp { get; set; } } }using LiteNetLib; using LiteNetLib.Utils; using MessagePack; using System; using System.Collections.Generic; using System.Text; namespace LiteNetServer { partial class MT { public static void ps(ListBox listBox1, string text) { if (listBox1.InvokeRequired) { listBox1.Invoke(new Action(() => listBox1.Items.Add("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + text))); } else { listBox1.Items.Add("[" + DateTime.Now.ToString("HH:mm:ss") + "] " + text); } } public static void SendListToClient<T>(Dictionary<int, NetPeer> clients, int clientid, MsgType msgType, List<T> ObjList) { if (clients.TryGetValue(clientid, out NetPeer peer) && peer.ConnectionState == ConnectionState.Connected) { var writer = new NetDataWriter(); writer.Put((byte)msgType); writer.Put(MessagePackSerializer.Serialize(ObjList)); peer.Send(writer, DeliveryMethod.ReliableOrdered); } else { } } } }using LiteNetLib.Utils; using MessagePack; using System; using System.Collections.Generic; using System.Text; namespace LiteNetServer { internal class MO { } // 必须加这个特性!MessagePack 序列化用 [MessagePackObject] public class OBJ01 { // 用 Key 标记序列化顺序(必须唯一) [Key(0)] public int id { get; set; } [Key(1)] public string aaa { get; set; } [Key(2)] public int x { get; set; } [Key(3)] public int y { get; set; } } [MessagePackObject] public class OBJ02 { [Key(0)] public int id { get; set; } [Key(1)] public string bbb { get; set; } [Key(2)] public int z { get; set; } } // 消息ID public enum MsgType : byte { OBJ01 = 1, OBJ02 = 2 } }