• UDP


     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;
            }
        }
    

      

  • 相关阅读:
    JPG bufffer转Mat
    cv:Mat MFC上显示 BitMatToWnd
    opencv 版本修改
    2个多边形的关系判断和相交面积计算
    截取图像 opencv
    SQL Server 存储过程的分页方案比拼
    XP系统下数据库文件夹的权限设置
    关于23种设计模式的有趣见解
    一些编程的好习惯
    sql server 2000的数据库还原
  • 原文地址:https://www.cnblogs.com/robertyao/p/12713496.html
Copyright © 2020-2023  润新知