internal class IocpUdpServer { private Socket _listen; private bool _isRun; private readonly int _bufferLength; //Sae池 private readonly SaeQueuePool _saeQueue = new SaeQueuePool(256); /// <summary> /// 获取SEA池中的可用项数量 /// </summary> public int SeaCount => _saeQueue.Count; /// <summary> /// 获取当前运行的IP /// </summary> public string Ip { get; } /// <summary> /// 获取系统分配的UDP端口号 /// </summary> public int Port { get; } /// <summary> /// /// </summary> public long ReceivedBytesCount { get; private set; } /// <summary> /// /// </summary> public long SendBytesCount { get; private set; } /// <summary> /// 收到的报文数量 /// </summary> public int ReceivedCount { get; private set; } /// <summary> /// 发送的报文数量 /// </summary> public int SendCount { get; private set; } /// <summary> /// /// </summary> public bool IsRunning => _isRun; //报文接收处理队列 private readonly IUdpRequestHandler _handlerQueue; /// <summary> /// 实例化UDP服务器,并直接启动监听 /// </summary> /// <param name="handlerQueue">报文接收处理队列</param> /// <param name="bufferLength">缓冲区大小</param> /// <param name="port">监听的端口号</param> public IocpUdpServer(IUdpRequestHandler handlerQueue, string ip, int port, int bufferLength = 1024) { _handlerQueue = handlerQueue; _bufferLength = bufferLength; Ip = ip; Port = port; } /// <summary> /// 收到数据事件 /// </summary> public event EventHandler<ReceiveDataEventArgs> ReceiveData; /// <summary> /// 启动UPD监听,接收来自网络上的UDP消息 /// </summary> public void Start() { //var local = new IPEndPoint(IPAddress.Any, Port); var local = new IPEndPoint(IPAddress.Any, Port); _listen = new Socket(local.AddressFamily, SocketType.Dgram, ProtocolType.Udp); _listen.Bind(local); var socketAsync = new SocketAsyncEventArgs(); socketAsync.SetBuffer(new byte[_bufferLength], 0, _bufferLength); socketAsync.Completed += SocketAsync_Completed; socketAsync.RemoteEndPoint = local; _isRun = true; StartReceive(socketAsync); } public void Stop() { Close(); } /// <summary> /// 开始异步接收UDP消息 /// </summary> private void StartReceive(SocketAsyncEventArgs socketAsync) { if (!_isRun) return; if (!_listen.ReceiveFromAsync(socketAsync)) SocketAsync_Completed(_listen, socketAsync); } private void SocketAsync_Completed(object sender, SocketAsyncEventArgs e) { if (e.BytesTransferred > 0 && e.SocketError == SocketError.Success) { if (e.LastOperation == SocketAsyncOperation.ReceiveFrom) { var data = new byte[e.BytesTransferred]; Buffer.BlockCopy(e.Buffer, e.Offset, data, 0, data.Length); if (Settings.DebugUdpPacket) LogConsole.Debug($"UDP Rcv:{data.ToHexString()},长度={data.Length}"); ReceivedBytesCount += e.BytesTransferred; ReceivedCount++; StartReceive(e); //Console.WriteLine($"{DateTime.Now} {e.RemoteEndPoint} {buffer.Length}"); OnReceive((IPEndPoint)e.RemoteEndPoint, data); return; } } StartReceive(e); } /// <summary> /// 远程端点收到消息处理 /// </summary> private void OnReceive(IPEndPoint iPEndPoint, byte[] data) { if (!_isRun) return; if (iPEndPoint == null) return; //小于8字节的报文不处理 if (data.Length < 8 + 4) { LogConsole.Debug("报文过短,抛弃:" + data.ToHexString()); return; } //UDP的到达顺序不确定性可能导致问题 //TODO:拆包 var prefix = data[0]; var subfix = data.Last(); if (prefix != G.FrameHeader || subfix != G.FrameTail) { LogConsole.Debug("收尾错误,抛弃:" + data.ToHexString()); return; } //Debug.WriteLine($"收到端点:{args.IpEndPoint},报文=> {data.ToHexString()}"); _handlerQueue.Enqueue(new UdpRequestWrapper(data, iPEndPoint)); //抛出收到数据事件 ReceiveData?.Invoke(this, new ReceiveDataEventArgs { Data = data, IpEndPoint = iPEndPoint }); } /// <summary> /// 向远程网络端点发送数据 /// </summary> public void SendAsync(EndPoint endPoint, byte[] bytes) { if (!_isRun || _listen == null) return; //优先从可复用队列中取 var socketSendAsync = _saeQueue.Dequeue(); socketSendAsync.SetBuffer(bytes, 0, bytes.Length); socketSendAsync.RemoteEndPoint = endPoint; SendCount++; SendBytesCount += bytes.Length; if (Settings.DebugUdpPacket) LogConsole.Debug($"UDP Send:{endPoint},Data={bytes.ToHexString()}"); //如果发送失败,则强制归队 if (!_listen.SendToAsync(socketSendAsync)) _saeQueue.Enqueue(socketSendAsync); } /// <summary> /// 关闭服务 /// </summary> public void Close() { _isRun = false; _listen?.Close(); _listen = null; } }