Netty入门与实战——服务端源码及启动流程
此系列文章来源于总结归纳Netty 入门与实战:仿写微信 IM 即时通讯系统
代码:
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.util.AttributeKey;
public class NettyServer {
private static final int BEGIN_PORT = 8000;
public static void main(String[] args) {
NioEventLoopGroup boosGroup = new NioEventLoopGroup(); //创建新连接
NioEventLoopGroup workerGroup = new NioEventLoopGroup(); //读取数据以及业务逻辑处理
final ServerBootstrap serverBootstrap = new ServerBootstrap(); //引导类,进行服务端的启动工作
final AttributeKey<Object> clientKey = AttributeKey.newInstance("clientKey");
serverBootstrap
.group(boosGroup, workerGroup) //给引导类配置两大线程组(线程模型)
.channel(NioServerSocketChannel.class) //指定IO模型为NIO
.attr(AttributeKey.newInstance("serverName"), "nettyServer") //给NioServerSocketChannel指定一些自定义属性,通过channel.attr()取出这个属性
.childAttr(clientKey, "clientValue") //给每一条连接指定自定义属性
.option(ChannelOption.SO_BACKLOG, 1024)//表示系统用于临时存放已完成三次握手的请求的队列的最大长度
.childOption(ChannelOption.SO_KEEPALIVE, true)//是否开启TCP底层心跳机制,true为开启
.childOption(ChannelOption.TCP_NODELAY, true)//是否开启Nagle算法,true表示关闭,false表示开启,通俗地说,如果要求高实时性,有数据发送时就马上发送,就关闭,如果需要减少发送次数减少网络交互,就开启。
.childHandler(new ChannelInitializer<NioSocketChannel>() {
protected void initChannel(NioSocketChannel ch) {
System.out.println(ch.attr(clientKey).get());
}
}); //定义后续每条连接的数据读写,业务处理逻辑
bind(serverBootstrap, BEGIN_PORT); //递增绑定端口
}
private static void bind(final ServerBootstrap serverBootstrap, final int port) {
serverBootstrap.bind(port).addListener(future -> {
if (future.isSuccess()) {
System.out.println("端口[" + port + "]绑定成功!");
} else {
System.err.println("端口[" + port + "]绑定失败!");
bind(serverBootstrap, port + 1);
}
});
}
}
解析:
*首先创建了两个NioEventLoopGroup
,这两个对象可以看做是传统IO编程模型的两大线程组,bossGroup
表示监听端口,accept 新连接的线程组,workerGroup
表示处理每一条连接的数据读写的线程组。类比为:一个工厂要运作,必然要有一个老板负责从外面接活,然后有很多员工,负责具体干活,老板就是bossGroup
,员工们就是workerGroup
,bossGroup
接收完连接,扔给workerGroup
去处理。
*然后创建了一个引导类 ServerBootstrap的对象
,这个类将引导我们进行服务端的启动工作
*通过.group(bossGroup, workerGroup)
给引导类配置两大线程组,指定引导类的线程模型
*通过.channel(NioServerSocketChannel.class)
来指定 IO 模型
*调用childHandler()
方法,给这个引导类创建一个ChannelInitializer
,定义后续每条连接的数据读写,业务处理逻辑
*ChannelInitializer
这个类中,NioSocketChannel
就是 Netty 对 NIO 类型的连接的抽象,前面NioServerSocketChannel
也是对 NIO 类型的连接的抽象
*递增地绑定端口,起始端口号BEGIN_PORT=8000,若绑定失败则端口号+1,直到绑定端口成功
总结:
1、创建一个引导类,然后给他指定线程模型,IO模型,连接读写处理逻辑,绑定端口之后,服务端就启动起来了。
2、bind 方法是异步的,我们可以通过这个异步机制来实现端口递增绑定。
3、Netty 服务端启动额外的参数,主要包括给服务端 Channel 或者客户端 Channel 设置属性值,设置底层 TCP 参数。