总览链接:
https://blog.youkuaiyun.com/a1234012340a/article/details/91040073
首先贴一下我的服务端代码
static async Task RunServerAsync()
{
//方法1
申明一个主回路调度组
//var dispatcher = new DispatcherEventLoopGroup();
主工作线程组,设置为1个线程
//IEventLoopGroup bossGroup = dispatcher; // (1)
工作线程组,设置为1个线程
//IEventLoopGroup workerGroup = new WorkerEventLoopGroup(dispatcher);
// 主工作线程组,设置为1个线程
//方法2
IEventLoopGroup bossGroup = new MultithreadEventLoopGroup(1);
// 工作线程组,默认为内核数*2的线程数
IEventLoopGroup workerGroup = new MultithreadEventLoopGroup(1);
try
{
// 声明一个服务端Bootstrap,每个Netty服务端程序,都由ServerBootstrap控制,通过链式的方式组装需要的参数
var serverBootstrap = new ServerBootstrap(); // (2)
// 设置主和工作线程组
serverBootstrap.Group(bossGroup, workerGroup)
//有数据立即发送
.Option(ChannelOption.TcpNodelay, true)
.ChildOption(ChannelOption.SoKeepalive, true);
// 申明服务端通信通道为TcpServerChannel
serverBootstrap.Channel<TcpServerSocketChannel>(); // (3)
serverBootstrap
// 设置网络IO参数等
.Option(ChannelOption.SoBacklog, 100) // (5)
// 在主线程组上设置一个打印日志的处理器
.Handler(new LoggingHandler("SRV-LSTN"))
// 设置工作线程参数
.ChildHandler(
/*
* ChannelInitializer 是一个特殊的处理类,他的目的是帮助使用者配置一个新的 Channel。
* 也许你想通过增加一些处理类比如DiscardServerHandler 来配置一个新的 Channel 或者其对应的ChannelPipeline 来实现你的网络程序。
* 当你的程序变的复杂时,可能你会增加更多的处理类到 pipline 上,然后提取这些匿名类到最顶层的类上。
*/
new ActionChannelInitializer<ISocketChannel>( // (4)
channel =>
{
/*
* 工作线程连接器是设置了一个管道,服务端主线程所有接收到的信息都会通过这个管道一层层往下传输,
* 同时所有出栈的消息 也要这个管道的所有处理器进行一步步处理。
*/
IChannelPipeline pipeline = channel.Pipeline;
// 添加日志拦截器
pipeline.AddLast(new LoggingHandler("SRV-CONN"));
// 添加出栈消息,通过这个handler在消息顶部加上消息的长度。
// LengthFieldPrepender(2):使用2个字节来存储数据的长度。
//pipeline.AddLast("framing-enc", new LengthFieldPrepender(2));
/*
入栈消息通过该Handler,解析消息的包长信息,并将正确的消息体发送给下一个处理Handler
1,InitialBytesToStrip = 0, //读取时需要跳过的字节数
2,LengthAdjustment = -5, //包实际长度的纠正,如果包长包括包头和包体,则要减去Length之前的部分
3,LengthFieldLength = 4, //长度字段的字节数 整型为4个字节
4,LengthFieldOffset = 1, //长度属性的起始(偏移)位
5,MaxFrameLength = int.MaxValue, //最大包长
*/
//pipeline.AddLast("framing-dec", new LengthFieldBasedFrameDecoder(ushort.