一个典型的netty服务端代码如下:
public class SocketServer {
public void run(int port) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch)
throws Exception {
ChannelPipeline pipeline = ch.pipeline();
//LengthFieldBasedFrameDecoder:TCP的解码器,可以靠它轻松搞定TCP粘包问题。
pipeline.addLast("frameDecoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
//构造函数传递要解码成的类型
//可以通过:protobuf方式进行解码和编码,以提高网络消息的传输效率。
pipeline.addLast("protobufDecoder", new ProtobufDecoder(CommonProto.CommonMessage.getDefaultInstance()));
//编码用
pipeline.addLast("frameEncoder", new LengthFieldPrepender(4, false));
pipeline.addLast("protobufEncoder", new ProtobufEncoder());
pipeline.addLast("readTimeOut", new ReadTimeoutHandler(1200,TimeUnit.SECONDS));
pipeline.addLast("handler",ServerSocketHandlerFactory.getInstance().getSingleSocketServerHandler());
}
});
// 设置相关参数
b.option(ChannelOption.SO_BACKLOG, 1024);
b.childOption(ChannelOption.SO_KEEPALIVE, true);
b.childOption(ChannelOption.TCP_NODELAY, true);
Channel ch = b.bind(port).sync().channel();
log.info("Normal socket server started at port " + port + '.');
ch.closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
在绑定端口的时候,最终调用到initAndRegister方法里的channelFactory.newChannel()生成一个服务的的channel,这里再深入下去可以看见,调用的是反射生产实列。就是前面channel(NioServerSocketChannel.class)中传入的class对象。
在反射实列化的时候调用NioServerSocketChannel的构造方法,设置ch.configureBlocking(false),最终调用jdk方法生成jdk的一个channel与该类绑定。再创建基本组件绑定channel如pipeline。再调用init方法初始化NioServerSocketChannel,为服务端Channel添加连接处理器,随后调用register()方法注册Selector,将JDK Channel注册到事件轮询器Selector上面,并将服务端Channel作为Attachment绑定到对应JDK底层Channel,最后调用doBind()方法实现对本地端口监听,绑定成功重新向Selector注册OP_ACCEPT事件接收新连接。至此,netty服务端启动完成。