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