添加库 最少以下两个
DotNetty.Common
DotNetty.Handlers
using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Handlers.Timeout;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using System.Text;
namespace CSharpAllDemo.Tcp
{
public class DotnettyManager
{
// 私有静态实例
private static readonly DotnettyManager _instance = new DotnettyManager();
// 公共静态方法,返回实例
public static DotnettyManager Instance => _instance;
private Dictionary<string, IChannelHandlerContext> mContextDictory = new();
private DotnettyManager() { }
public async Task InitAsync(int port)
{
// 主工作线程组,设置为1个线程
var bossGroup = new MultithreadEventLoopGroup(1);
// 工作线程组,默认为内核数*2的线程数
var workerGroup = new MultithreadEventLoopGroup();//声明一个服务端Bootstrap,每个Netty服务端程序,都由ServerBootstrap控制,
//通过链式的方式组装需要的参数
var bootstrap = new ServerBootstrap();
bootstrap
.Group(bossGroup, workerGroup) // 设置主和工作线程组
.Channel<TcpServerSocketChannel>() // 设置通道模式为TcpSocket
.Option(ChannelOption.SoBacklog, 100) // 设置网络IO参数等,这里可以设置很多参数,当然你对网络调优和参数设置非常了解的话,你可以设置,或者就用默认参数吧
.Option(ChannelOption.SoKeepalive, true)//保持连接
//.Option(ChannelOption.RcvbufAllocator, new FixedRecvByteBufAllocator(4000))
.ChildHandler(new ActionChannelInitializer<ISocketChannel>(channel =>
{
//工作线程连接器 是设置了一个管道,服务端主线程所有接收到的信息都会通过这个管道一层层往下传输
//同时所有出栈的消息 也要这个管道的所有处理器进行一步步处理
IChannelPipeline pipeline = channel.Pipeline;
pipeline.AddLast(new CommonServerDecoder());
pipeline.AddLast(new CommonServerEncoder());
pipeline.AddLast(new IdleStateHandler(5, 0, 0));
//业务handler ,这里是实际处理业务的Handler
pipeline.AddLast(new TcpServerHandler());
}));
// bootstrap绑定到指定端口的行为 就是服务端启动服务,同样的Serverbootstrap可以bind到多个端口
IChannel boundChannel = await bootstrap.BindAsync(port);
}
public void Send(string deviceId, byte[] message)
{
mContextDictory[deviceId]?.WriteAndFlushAsync(message);
}
}
class TcpServerHandler : ChannelHandlerAdapter
{
public override void ChannelRead(IChannelHandlerContext context, object message)
{
if (message is byte[] o)
{
string srt = Encoding.UTF8.GetString(o);
context.WriteAndFlushAsync(srt);
//System.Diagnostics.Debug.WriteLine($"byte方式,从服务端接收:{Encoding.UTF8.GetString(o)}");
}
}
public override void UserEventTriggered(IChannelHandlerContext context, object evt)
{
if (evt is IdleStateEvent)
{
IdleStateEvent e = evt as IdleStateEvent;
if (e.State == IdleState.AllIdle)
{
//读或者写
System.Diagnostics.Debug.WriteLine("==AllIdle==");
}
else if (e.State == IdleState.ReaderIdle)
{
//读
System.Diagnostics.Debug.WriteLine("==ReaderIdle==");
}
else if (e.State == IdleState.WriterIdle)
{
System.Diagnostics.Debug.WriteLine("==WriterIdle==");
}
}
}
}
class CommonServerDecoder : ByteToMessageDecoder
{
protected override void Decode(IChannelHandlerContext context, IByteBuffer input, List<object> output)
{
byte[] array = new byte[input.ReadableBytes];
input.GetBytes(input.ReaderIndex, array, 0, input.ReadableBytes);
input.Clear();
output.Add(array);
}
}
class CommonServerEncoder : MessageToByteEncoder<string>
{
protected override void Encode(IChannelHandlerContext context, string message, IByteBuffer output)
{
byte[] messageBytes = Encoding.UTF8.GetBytes(message);
IByteBuffer initialMessage = Unpooled.Buffer(messageBytes.Length);
initialMessage.WriteBytes(messageBytes);
output.WriteBytes(initialMessage);
}
}
}