当你了:
解了阻塞模型
非阻塞模型
react模型
知道这些原理之后,你不得不惊叹于netty的设计
selector 多路复用: 单线程可以配合 Selector 完成对多个 Channel 可读写事件的监控,这称之为多路复用;
0拷贝:splice函数的作用是将两个文件描述符之间建立一个管道,然后将文件描述符的引用传递过去,这样在使用到数据的时候就可以直接通过引用指针访问到具体数据,之前是拷贝数据,现在变为了传递映射指针,然后直接访问到数据;
缓冲区 :我认为缓冲区是netty提升性能的基础,有了缓冲区,才能实现多路复用,缓冲区相当于是netty传递消息的载体,贯穿整个netty;
随便拿出来一个都能吊打各路高手,netty集万千高级思想于一身
这要从TCP协议,缓冲区说起了;
这里面 缓冲区就是在传输过程中的一个缓冲的地方,他如果很大, 他就会讲小的消息体整合发送,他如果很小,就会将一个完整的消息体拆分下,然后发送;
会导致消息解析出现问题, 因为可能接受的消息不完整,也可能接受的消息是两部分,导致接受到后无法正确解析语义;
比较常见的就是DelimiterBasedFrameDecoder 用此种方式实现
用自定义分隔符作为一个消息的结束,解析即可
bootstrap.group(parentGroup, childGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 1024)
//接收套接字缓冲区大小
.option(ChannelOption.SO_RCVBUF, 1024 * 1024)
//发送套接字缓冲区大小
.option(ChannelOption.SO_SNDBUF, 1024 * 1024)
.option(ChannelOption.SO_KEEPALIVE, true)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
// 这里将FixedLengthFrameDecoder添加到pipeline中,指定长度为100
// pipeline.addLast(new FixedLengthFrameDecoder(100));
//这里将LineBasedFrameDecoder添加到pipeline中,设置最大长度为1024
// pipeline.addLast(new LineBasedFrameDecoder(1024));
//被按照$_$进行分隔,这里1024指的是分隔的最大长度,即当读取到1024个字节的数据之后,
// 若还是未读取到分隔符,则舍弃当前数据段,因为其很有可能是由于码流紊乱造成的
ByteBuf delimiter = copiedBuffer(Constants.MESSAGE_DELIMITER.getBytes(Charset.forName("UTF-8")));
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, delimiter));
// StringEncoder:字符串编码器,将String编码为将要发送到Channel中的ByteBuf
pipeline.addLast(new StringEncoder(Charset.forName("UTF-8")));
// StringDecoder:字符串解码器,将Channel中的ByteBuf数据解码为String
pipeline.addLast(new StringDecoder(Charset.forName("UTF-8")));
//绑定处理器(可绑定多个)
pipeline.addLast(new ServerHandler()); //处理业务
}
});
作为解析方,只需要根据分隔符作为消息分割即可,然后就能正确解析消息了;
netty真的是网络通讯中的王者,很多优秀的RPC框架,通讯等,底层都是采用netty作为通讯手段,之后还会写几篇netty的文章;