• UDP对像库加线程并行发送


     internal class IocpUdpServer
        {
            private Socket _listen;
            private bool _isRun;
            private readonly int _bufferLength;
            private readonly SaeQueuePool _saeQueue = new SaeQueuePool(512);
            /// <summary>
            /// 获取系统分配的UDP端口号
            /// </summary>
            public int Port { get; set; }
    
            //报文接收处理队列
            private readonly IUdpRequestHandler _handlerQueue;
    
            /// <summary>
            ///  发送缓存
            /// </summary>
            private readonly BufferBlock<SendInfo> _sendBlocking = new BufferBlock<SendInfo>(new DataflowBlockOptions()
            {
                BoundedCapacity = 256
            });
            private readonly ActionBlock<SendInfo> _sendAction; //操作 
            DefaultObjectPool<SocketAsyncEventArgs> recPool;
            /// <summary>
            /// 实例化UDP服务器,并直接启动监听
            /// </summary>
            /// <param name="handlerQueue">报文接收处理队列</param>
            /// <param name="bufferLength">缓冲区大小</param>
            /// <param name="port">监听的端口号</param>
            public IocpUdpServer(IUdpRequestHandler handlerQueue, int port, int bufferLength = 1024)
            {
                _handlerQueue = handlerQueue;
                _bufferLength = bufferLength;
                Port = port;
    
                var recPolicy = new DefaultPooledObjectPolicy<SocketAsyncEventArgs>();
                recPool = new DefaultObjectPool<SocketAsyncEventArgs>(recPolicy);
                _sendAction = new ActionBlock<SendInfo>(pkg =>
                {
                    try
                    {
                        var socketSendAsync = _saeQueue.Dequeue();
                        if (socketSendAsync == null)
                            return;
                        socketSendAsync.SetBuffer(pkg.bytes, 0, pkg.bytes.Length);
                        socketSendAsync.RemoteEndPoint = pkg.endPoint;
                        if (!_listen.SendToAsync(socketSendAsync))
                        {
                            _saeQueue.Enqueue(socketSendAsync);
                            LogHelper.WriteInfoLog("UDP发送失败报文:" + pkg.bytes.ToHexString());
                            Thread.Yield();
                        }
                    }
                    catch (Exception ex)
                    {
                        LogHelper.WriteErrLog("UDP发送失败:", ex);
                    }
                }, new ExecutionDataflowBlockOptions
                {
                    MaxDegreeOfParallelism = 3,
                });
    
                _sendBlocking.LinkTo(_sendAction);
            }
    
    
    
    
    
            /// <summary>
            /// 启动UPD监听,接收来自网络上的UDP消息
            /// </summary>
            public void Start()
            {
                if (!_isRun)
                {
                    var local = new IPEndPoint(IPAddress.Any, Port);
                    _listen = new Socket(local.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
                    _listen.Bind(local);
    
                    var socketAsync = recPool.Get();
                    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);
                        StartReceive(e);
                        OnReceive((IPEndPoint)e.RemoteEndPoint, data);
                        recPool.Return(e);
                        return;
                    }
                }
                StartReceive(e);
            }
    
            /// <summary>
            /// 远程端点收到消息处理
            /// </summary>
            private void OnReceive(IPEndPoint iPEndPoint, byte[] data)
            {
                if (!_isRun)
                    return;
    
                //小于8字节的报文不处理
                //if (data.Length < 8 + 4)
                //{
                //    LogHelper.WriteInfoLog("报文过短,抛弃:" + data.ToHexString());
                //    return;
                //}
    
                //UDP的到达顺序不确定性可能导致问题
                //TODO:拆包
                var prefix = data.First();
                var subfix = data.Last();
                if (prefix != G.FrameHeader || subfix != G.FrameTail)
                {
                    LogHelper.WriteInfoLog("收尾错误,抛弃:" + data.ToHexString());
                    return;
                }
                _handlerQueue.Enqueue(new UdpRequestWrapper(data, iPEndPoint));
    
            }
    
            /// <summary>
            /// 向远程网络端点发送数据
            /// </summary>
            public async void SendAsync(EndPoint endPoint, byte[] bytes)
            {
                if (!_isRun || _listen == null)
                    return;
                var sendInfo = new SendInfo
                {
                    endPoint = endPoint,
                    bytes = bytes
                };
                await _sendBlocking.SendAsync(sendInfo);
    
    
    
    
                //优先从可复用队列中取  
                //var socketSendAsync = _saeQueue.Dequeue();
                //socketSendAsync.SetBuffer(bytes, 0, bytes.Length);
                //socketSendAsync.RemoteEndPoint = endPoint;
    
                ////如果发送失败,则强制归队
                //if (!_listen.SendToAsync(socketSendAsync))
                //    _saeQueue.Enqueue(socketSendAsync);
            }
    
            /// <summary>
            /// 关闭服务
            /// </summary>
            public void Close()
            {
                _isRun = false;
                _listen?.Close();
                _listen = null;
            }
        }
    
    
        internal class SendInfo
        {
            public EndPoint endPoint { get; set; }
            public byte[] bytes { get; set; }
    
        }
    !_listen.SendToAsync(socketSendAsync)

    如果I/O操作挂起,则为true。这个System.Net.Sockets接口.SocketAsyncEventArgs。已完成操作完成后将引发e参数上的事件。

    如果I/O操作同步完成,则返回false。

    在这种情况下System.Net.Sockets接口.SocketAsyncEventArgs。已完成不会引发e参数上的事件,并且可以在方法调用返回以检索操作结果后立即检查作为参数传递的e对象。

    public const byte FrameHeader = 0x7E;

    /// <summary>
    /// 命令帧帧尾(0x7F)
    /// </summary>
    public const byte FrameTail = 0x7F;

  • 相关阅读:
    NGUI Sprite 和 Label 改变Layer 或父物体后 未更新深度问题
    unity销毁层级物体及 NGUI 深度理解总结
    unity 2d 和 NGUI layer
    关于NGUI与原生2D混用相互遮盖的问题心得
    CentOS7为firewalld添加开放端口及相关操作
    Python 操作redis有序集合(sorted set)
    win10下安装redis 服务
    python2/3中 将base64数据写成图片,并将图片数据转为16进制数据的方法、bytes/string的区别
    解决最小化安装Centos7后无法上网的问题,以及安装成功后的基本配置
    在mysql中使用group by和order by取每个分组中日期最大一行数据,亲测有效
  • 原文地址:https://www.cnblogs.com/robertyao/p/13959390.html
Copyright © 2020-2023  润新知