netty知识总结
Posted better_hui
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了netty知识总结相关的知识,希望对你有一定的参考价值。
目录
MTU(Maximun Transmission Unit)
一、tcp & udp
tcp : 面向连接 ;基于流 ;可靠的;仅支持一对一;首部开销20b;全双工可靠信道
udp:无连接;基于报文;不可靠;支持一对多、多对一、多对多通信;首部开销小8b;不可靠信道
二、tcp如何保证更可靠
1、确认应答和序列号
TCP传输时,将数据流进行编号,这就是序列号 ;可以用来应答、数据排序去重
每次接收方收到数据后,对川蜀坊进行应答,也就是发送ack报文
2、超时重传
TCP发出一段后,启动一个定时器,等待目标端ack报文,如不能及时收到确认,则重新发送报文
3、流量控制
tcp链接双方均有一个固定大小的缓冲空间,tcp接收端只允许发送端发送缓冲区能够接纳大小的数据。
当接收方来不及处理发送方数据时,能够提示发送方降低速率,防止包丢失
tcp流量控制协议是可变大小的滑动窗口协议
4、拥塞控制
当网络阻塞时,发送方继续重发,会加重网络阻塞,所以当出现阻塞时,应该控制发送方的速率。拥塞控制是为了控制网络的阻塞程度。
TCP 主要通过四个算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。
三、滑动窗口
滑动窗口是tcp流量控制的协议。假设我们每次发送一个数据包,然后就等待ack应答 ,这样会极大的影响传输效率,所以,我们把多个数据包达成一个package,一起发送出去,然后一起等待 。我们能够一起发送的数据量大小 , 就是窗口。
我们每次发送固定大小的窗口的数据 ,然后等待ack ,可行吗?答案是否定的。
窗口设置小了 : 需要频繁的接收数据的ack应答
窗口设置大了: 接收端处理不过来,会阻塞我们的网络。
所以我们需要一个动态的窗口:接收方来告诉我,可以处理多少数据 , 这就是提出窗口;发送方根据提出窗口和 已发送但是未确认的量 , 来计算可用窗口的大小。
我们可以把数据看做一条链 , 有一个可以向后滑动的窗口,框柱了 已发送待确认和允许发送的数据段
TCP的包可以分为四种状态
-
已发送并且已经确认的包。
-
已发送但是没有确认的包。
-
未发送但是可以发送的包。
-
不允许被发送的包。
零窗口 :当接收方提出窗口= 0 ,发送方只能停止发送。但是会建立一个零窗口定时探测器,向接收方询问窗口大小,当不在是0时 , 就可以继续发送了。
四、状态流转
LISTEN:等待从任何远端TCP 和端口的连接请求。 SYN_SENT:发送完一个连接请求后等待一个匹配的连接请求。 SYN_RECEIVED:发送连接请求并且接收到匹配的连接请求以后等待连接请求确认。 ESTABLISHED:表示一个打开的连接,接收到的数据可以被投递给用户。连接的数据传输阶段的正常状态。 FIN_WAIT_1:等待远端TCP 的连接终止请求,或者等待之前发送的连接终止请求的确认。 FIN_WAIT_2:等待远端TCP 的连接终止请求。 CLOSE_WAIT:等待本地用户的连接终止请求。 CLOSING:等待远端TCP 的连接终止请求确认。 LAST_ACK:等待先前发送给远端TCP 的连接终止请求的确认(包括它字节的连接终止请求的确认) TIME_WAIT:等待足够的时间过去以确保远端TCP 接收到它的连接终止请求的确认。 TIME_WAIT 两个存在的理由: 1.可靠的实现tcp全双工连接的终止; 2.允许老的重复分节在网络中消逝。 CLOSED:不在连接状态(这是为方便描述假想的状态,实际不存在)
五、粘包、拆包
tcp是流协议,本身是无界限的。tcp会根据实际情况划分发送,一个完整的数据包可能拆分成多个,也可以整合成一个进行发送,这就是拆包、粘包
MTU(Maximun Transmission Unit)
最大传输单元,在数据链路层中,规定MTU大小,以太网 设置为1500字节
MSS(Maximun Segment Size)
最大保温段 , MSS = MTU - IP首部(20)- TCP首部(20) = 1460
1、引起拆包、粘包的原因
1、应用程序写入的数据 超过了套接字缓存大小 , 发生拆包
2、应用程序写入的数据小于套接字缓存,缓存会整合多个数据,统一发送到网络上,发生粘包
3、接收方法不能即时读取套接字缓存区数据,发生粘包
2、tcp解决方案
1、消息定长
2、分隔符
3、消息头,规定数据长度
3、netty解决方案
1、FixedLengthFrameDecoder 消息定长
2、LineBasedFrameDecoder 换行符 和 DelimiterBasedFrameDecoder (用户自定义风格福)
3、LengthFieldBasedFrameDecoder 数据包中添加一个长度的字段
4、自定义编码、解码器
六、同步、异步、阻塞、非阻塞
-
同步,就是我调用一个功能,该功能没有结束前,我死等结果。
-
异步,就是我调用一个功能,不需要知道该功能结果,该功能有结果后通知我(回调通知)
-
阻塞,就是调用我(函数),我(函数)没有接收完数据或者没有得到结果之前,我不会返回。
-
非阻塞,就是调用我(函数),我(函数)立即返回,通过select通知调用者
同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞
阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回
七、网络IO模型
八、BIO、NIO、AIO
1、BIO , 同步且阻塞 , 一个请求一个线程,对服务器要求高,适用于连接数比较小且固定的架构,开发难度小
2、NIO,同步非阻塞 ,客服端的链接请求注册到多路复用器上,多路复用器轮询到有链接IO时,转给一个线程处理,自己继续阻塞等待,jdk1.4开始支持
3、AIO ,异步非阻塞,客户端的IO请求由内内核理完成,然后通知业务线程处理,适用于连接数多 且 链接较长的架构。jdk7 开始支持
九、select 、poll 、 epoll
1、链接数
select : 1024个 , 单个进程能打开的最大连接数 有FD_ZETSIZE 决定
poll : 没有上限,采用链表的方式
epoll : 链接数有上限,但是很大,1G内存支持10万的链接
2、轮询方式
select : 普通轮询 , 当连接数过大时,性能较差
poll : 同上
epoll : 采用回调的方式 , 链接的socket注册到epoll上 , 当有数据读写时,调用callBack
3、数据copy
select: 内核空间拷贝至用户空间 ,非常耗时
poll : 同上
epoll : 内核空间和用户空间 共享一块内存空间,相当于是零拷贝
十、netty 优点
NIO:
1、nio类库、api学习成本高,复杂
2、失败重试、数据丢失、拆包粘包等问题
3、selectk空轮训,内存飚增
netty:
1、架构设计优雅简单,耦合度低,底层模型可以使用不同网络协议
2、提供多种标准协议、安全、编码解码的支持
3、降低了NIO使用难度
4、很多开源框架都在使用,dubbo /rocketmq/spark
5、零拷贝、统一的api、标准可扩展的时间模型
十一、netty的组件
1、channel
2、buffer
3、EventLoop
4、ChannelHandler 和 ChannelPipeline
5、Bootstrap 和 ServerBootstrap
十二、什么是netty
1、netty是基于java nio(IO多路复用)的网络通信框架 ,极大的简化了TCP、UDP套接字服务的网络编程, 并且性能与安全性、使用性上更好。
2、特点:采用的reactor线程模型,是异步非阻塞、基于事件驱动、高性能、高可靠性和高定制型
3、支持多种协议、多种粘包拆包及二次编码机制。
4、使用范围广泛,比如dubbo/rocketMQ , Elasticsearch/gRPC等等
十三、为什么使用netty
1、简单易用,为我们屏蔽jdk自带的java nio的复杂度。
2、优秀的线程模型 reactor , 性能高 ,且零维护
3、功能强大,预置了多种编解码器,支持多种主流协议
4、高定制性,通过ChannelHandler 对通信框架进行灵活扩展
5、安全性高,有完整的SSL/TLS等支持
6、社区活动、网上教程多
7、使用广泛,在互联网、大数据、网络游戏等领取广泛应用,且满足商业标准
十四、应用场景
理论上NIO可以做的事情,使用netty都可以做。
1、作为RPC框架的网络通信工具:DUBBO、GRPC
2、用作HTTP服务器,目前我们常见的web服务器都是基于toncat或者jetty的 , 是基于serlet的 , NIO支持更底层的TCP协议,所以也可以用作支撑HTTP服务器,目前netty 就是http的协议支持。
3、即时的通讯系统,比如聊天工具 或者 聊天室,这块开源项目比较多的
4、消息推送系统。比如rocketMQ
十五、重要组件
1、bootstrap / serverbootstrap
bootstrap是netty的引导程序,采用了构造者模式,包含了线程组、通道channel、handler等配置信息。
引导netty的启动:
1、new NioEventLoop的构造方法里打开了一个多路复用器
2、serverBootstrap.bind()
2.1、创建一个ServerSocketChannel (initAndRegister())
2.2、绑定一个端口,先注册0事件 ,因为这时 项目还未完全启动
AbstractChannel对象的
selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
2.3、真正的绑定 DefaultChannelPipeline.HeadContext -> AbstractChannel.Head
javaChannel().bind(localAddress, config.getBacklog());
ServerBootstrapAcceptor请求接收器,将boss线程接收到的链接请求封装转发给worker线程
public void channelRead(ChannelHandlerContext ctx, Object msg) { try { childGroup.register(child).addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { forceClose(child, future.cause()); } } }); } catch (Throwable t) { forceClose(child, t); } }
2、nioEventLoopGroup/nioEventLoop
netty的线程池和执行线程。
nioEventLoopGroup : 提供了创建、获取nioEventLoop、注册channel的方法。
nioEventLoop : 我们可以看做是线程的扩展,该对象主要负责监听网络事件 并调用事件处理器进行相关的操作。
3、channel
channel接口是netty 对网络操作的抽象 , 包含了基本的IO操作,如bind()/connet()/read()/write()等 , 其主要实现如下:
NioserverSocketChannel , 对应 java nio的 ServerSocketChannel
NioSocketChannel , 对应 java nio的 SocketChannel
4、channelFuture
netty是异步非阻塞 , 我们在发起调用后 , 有可能不能立刻得到我们期待的结果, 所以我们通过channelFuture.addListener ,添加一个回调。
另外我们还可以通过sync , 是的异步非阻塞变为同步阻塞式调用
5、channelPipeline
channelPipeline是channelHandler的双向链表,提供了一个容器定义并处理流转与处理器链上的channel。
一个channel只能绑定于一个channelPipeline , 也就只能在此容器内流转 ,局部范围内是串行的,没有线程安全问题
channelPipeline 定义了handler的head和tail , 可以沿着责任链依次处理。
6、channelHandler
是netty消息的具体处理器,负责处理连接、读、写等操作。
十三、高性能
基于I/O多路复用模型
零拷贝
基于NIO的Buffer
基于内存池的缓冲区重用机制
无锁化的串行设计理念
I/O操作的异步处理
提供对protobuf等高性能序列化协议支持
可以对TCP进行更加灵活地配置
以上是关于netty知识总结的主要内容,如果未能解决你的问题,请参考以下文章