DotNetty 封装的TcpClient

.net 里 Netty 资料不多,做个记录

public class NetworkCommunicator : ICommunicator
{
    #region Netty 本来想用静态,后来觉得多个client公用一个netty可能分不清返回的数据, 先这样,后期要是吃资源再优化
    Bootstrap _NettyBoot;
    IEventLoopGroup _NettyEventLoop;
    IChannel _NettyChannel;
    private TaskCompletionSource<byte[]> _ResponseCompletionSource;
    CancellationTokenSource _TokenSource;
    NettyDataHandler _NettyDataHandler;
    object sendLock = new object();
    void NettyServerInit()
    {
        // Loop可以指定线程数量来提升负载,如果不设定则是默认cpu核心数为线程数,我不确定系统 tcp 的使用情况,没法确定这里的线程
        _NettyEventLoop ??= new MultithreadEventLoopGroup();
        if (_NettyBoot is null)
        {
            _NettyDataHandler = new NettyDataHandler();
            _NettyBoot = new Bootstrap();
            _NettyBoot.Group(_NettyEventLoop)
                .Channel<TcpSocketChannel>()
                .Option(ChannelOption.TcpNodelay, true)
                .Handler(new ActionChannelInitializer<ISocketChannel>(channel =>
                {
                    IChannelPipeline pipeline = channel.Pipeline;
                    pipeline.AddLast(_NettyDataHandler); // Add your handler here
                }));
        }
    }
    class NettyDataHandler : ChannelHandlerAdapter
    {
        public event Func<byte[], Task>? OnBytesReceived;
        public event Action? OnDisconnected;
        public override void ChannelRead(IChannelHandlerContext context, object message)
        {
            if (message is IByteBuffer byteBuffer)
            {
                byte[] bytes = new byte[byteBuffer.ReadableBytes];
                byteBuffer.GetBytes(byteBuffer.ReaderIndex, bytes);
                OnBytesReceived?.Invoke(bytes);
            }
        }
        public override void ChannelReadComplete(IChannelHandlerContext context)
        {
            context.Flush();
        }

        public override void ExceptionCaught(IChannelHandlerContext context, Exception e)
        {
            context.CloseAsync();
            OnDisconnected?.Invoke();
        }
    }
    #endregion
    public IPEndPoint? LocalEndPoint { get; private set; }

    public IPEndPoint? RemoteEndPoint { get; private set; }

    public bool IsConnected
    {
        get
        {
            if (_NettyChannel is null) return false;
            return _NettyChannel.Open && _NettyChannel.Registered;
        }
    }

    public event Action<byte[]> OnDataReceive;
    internal NetworkCommunicator()
    {
        LocalEndPoint = new IPEndPoint(IPAddress.Any, 0);
        NettyServerInit();
        _NettyDataHandler!.OnBytesReceived += receiveByte => Task.Run(() =>
        {
            OnDataReceive?.Invoke(receiveByte);
            _ResponseCompletionSource?.TrySetResult(receiveByte);
        });


    }
    internal NetworkCommunicator(IPEndPoint localEndPoint)
    {
        LocalEndPoint = localEndPoint;
        NettyServerInit();
        _NettyDataHandler!.OnBytesReceived += receiveByte => Task.Run(() =>
        {
            OnDataReceive?.Invoke(receiveByte);
            _ResponseCompletionSource?.TrySetResult(receiveByte);
        });
    }

    public bool Connect(IPEndPoint remoteEndPoint)
    {
        try
        {
            this.RemoteEndPoint = remoteEndPoint;
            if (!IsConnected)
            {
                _NettyChannel = _NettyBoot.ConnectAsync(RemoteEndPoint).Result;
                return Connect(remoteEndPoint);
            }
            return true;
        }
        catch (AggregateException ex)
        {
            Log4Helper.Communication.Error(ex);
            return false;
        }

    }

    public bool DisConnect()
    {
        _NettyChannel?.DisconnectAsync();
        return true;

    }

    public void Dispose()
    {

        _NettyChannel?.CloseAsync();
        _NettyEventLoop?.ShutdownGracefullyAsync();
        _NettyEventLoop = null;
        _NettyChannel = null;
    }

    public byte[]? Send(byte[]? content)
    {
        lock (sendLock)
        {
            _ResponseCompletionSource = new TaskCompletionSource<byte[]>();
            using (_TokenSource = new CancellationTokenSource(1000))
            {
                _TokenSource.Token.Register(() => _ResponseCompletionSource.TrySetCanceled(), useSynchronizationContext: false);
                SendAsync(content).Wait();
                try
                {
                    return _ResponseCompletionSource.Task.Result;
                }
                catch (TaskCanceledException)
                {
                    return null;
                }
                catch (AggregateException)
                {
                    return null;
                }
            }
        }
    }

    public async Task<bool> SendAsync(byte[]? content)
    {
        if (content is null) return false;
        if (RemoteEndPoint is null) return false;
        if (_NettyChannel is null)
        {
            Connect(RemoteEndPoint);
            return await (SendAsync(content));
        }
        var buffer = Unpooled.WrappedBuffer(content);
        await _NettyChannel.WriteAndFlushAsync(buffer);
        return true;
    }
}

 

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