DotNetty 封装的 UdpClient

DotNetty 资料较少,UdpClient 和 TcpClient 略有不同

public class UdpCommunicator : ICommunicator
{
    private IChannel? _ClientChannel;
    private Bootstrap? _Bootstrap;
    IEventLoopGroup? _LoopGroup;
    private TaskCompletionSource<byte[]> _ResponseCompletionSource;
    CancellationTokenSource _TokenSource;
    NettyDataReceiveHandle _NettyDataReceiveHandle = new NettyDataReceiveHandle();
    public IPEndPoint? LocalEndPoint { get; private set; }
    public IPEndPoint? RemoteEndPoint { get; private set; }

    public bool IsConnected { get; private set; }

    public event Action<byte[]> OnDataReceive;
    internal UdpCommunicator()
    {
        LocalEndPoint = new IPEndPoint(IPAddress.Any, 0);
        InitNetty();
    }
    /// <summary>
    /// 用于绑定的本地端点
    /// </summary>
    /// <param name="iPEndPoint"></param>
    internal UdpCommunicator(IPEndPoint iPEndPoint)
    {
        LocalEndPoint = iPEndPoint;
        InitNetty();
    }
    void InitNetty()
    {
        _NettyDataReceiveHandle.OnBytesReceived += receiveBytes => Task.Run(() =>
        {
            OnDataReceive?.Invoke(receiveBytes);
            _ResponseCompletionSource?.TrySetResult(receiveBytes);
        });
        _NettyDataReceiveHandle.OnDisconnected += () => IsConnected = false;

        _LoopGroup = new MultithreadEventLoopGroup();
        
    }

    public bool Connect(IPEndPoint remoteEndPoint)
    {
        try
        {

            RemoteEndPoint = remoteEndPoint;

            _Bootstrap = new Bootstrap();
            _Bootstrap
                .Group(_LoopGroup)
                .Channel<SocketDatagramChannel>()
                .Option(ChannelOption.SoBroadcast, true)
                .Handler(new ActionChannelInitializer<IChannel>(channel =>
                {
                    IChannelPipeline pipeline = channel.Pipeline;
                    pipeline.AddLast(_NettyDataReceiveHandle);
                }));

            _ClientChannel = _Bootstrap.BindAsync(LocalEndPoint).Result;
            return true;
        }
        catch (Exception ex)
        {
            return false;
        }

    }

    public bool DisConnect()
    {
        _ClientChannel?.CloseAsync().Wait();
        _ClientChannel = null;
        return true;
    }

    public void Dispose()
    {
        DisConnect();
        _LoopGroup?.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)).Wait();
        _LoopGroup = null;
    }
    object sendLock = new object();
    public byte[]? Send(byte[]? content)
    {
        lock (sendLock)
        {
            _ResponseCompletionSource = new TaskCompletionSource<byte[]>();
            using (_TokenSource = new CancellationTokenSource(600))
            {
                _TokenSource.Token.Register(() => _ResponseCompletionSource.TrySetCanceled(), useSynchronizationContext: false);
                bool sendResult = SendAsync(content).Result;
                if(!sendResult) return null;
                try
                {
                    return _ResponseCompletionSource.Task.Result;
                }
                catch (TaskCanceledException)
                {
                    _ResponseCompletionSource = null;
                    return null;
                }
                catch (AggregateException)
                {
                    _ResponseCompletionSource = null;
                    return null;
                }
            }
        }
    }

    public async Task<bool> SendAsync(byte[]? content)
    {
        if(_ClientChannel is null) return false;
        IByteBuffer byteBuffer = Unpooled.WrappedBuffer(content);
        await _ClientChannel.WriteAndFlushAsync(new DatagramPacket(byteBuffer, RemoteEndPoint));
        return true;
    }
}
class NettyDataReceiveHandle : SimpleChannelInboundHandler<DatagramPacket>
{
    public override bool IsSharable => true;
    public event Func<byte[], Task>? OnBytesReceived;
    public event Action? OnDisconnected;
    protected override void ChannelRead0(IChannelHandlerContext ctx, DatagramPacket packet)
    {
        var byteBuffer = packet.Content;
        byte[] bytes = new byte[byteBuffer.ReadableBytes];
        byteBuffer.GetBytes(byteBuffer.ReaderIndex, bytes);
        OnBytesReceived?.Invoke(bytes);
    }
    public override void ChannelReadComplete(IChannelHandlerContext ctx)
    {
        ctx.Flush();
    }

    public override void ExceptionCaught(IChannelHandlerContext ctx, Exception e)
    {
        ctx.CloseAsync();
        OnDisconnected?.Invoke();
    }
}

 

posted @ 2024-02-04 15:25  cchong005  阅读(174)  评论(0编辑  收藏  举报