1. Netty的由来
在很早之前,java已经提供了支持网络编程的IO包,但它属于阻塞IO,性能远不如采用C++或其它语言进行开发的网络编程。在jdk1.4后引入了NIO库,弥补了同步阻塞IO的不足,虽然使用NIO开发网络编程能够取得较好的性能,但基于原生NIO库进行开发,其固有的复杂性如网络闪断、客户端重连、安全认证、半包读写等,导致开发难度较高,不仅影响开发效率,而且维护性和稳定性也较差
Netty是一个异步且基于事件驱动的网络应用框架,它的优势在于降低开发难度、功能强大(可预制多种编解码功能,支持多种主流协议)、可定制和灵活性强、成熟稳定且社区活跃度高
2. Netty请求处理模型
Netty是一个IO复用模型,通过共用一个阻塞对象来接受多个外部请求,并将请求分发到线程池中的线程进行处理,其底层基于Reactor模型的主从Reactor多线程实现,即BossGroup线程维护Selector,只关注Accept客户端连接请求,WorkerGroup线程监听到感兴趣的事件后进行Handler读写处理等
3. TCP的粘包和拆包以及解决方案
Netty进行数据传输通常依靠TCP协议进行,我们知道TCP是以流数据进行传输,数据流之间没有明确的界限,因此很容易产生粘包和拆包的情况,如以下几种情况:
1. 当每次发送的数据小于发送缓冲区大小时,发送缓冲区会将多次发送的数据合并一同发送,会产生粘包
2. 当发送数据大于接收缓冲区的剩余大小时,导致剩余部分数据与其他数据在下一次到达接收缓冲区产生粘包
3. 当发送数据大于发送缓冲区大小时,会造成拆包
4. 当发送数据大于最大报文传输大小,会造成拆包
通用的解决方案:
1. 数据大小定长,让发送数据固定大小发送和接收,大小不足则空格填充;
2. 数据包的尾部添加分割符进行分割和区分;
3. 添加一个额外的字段表示数据的消息头,头部指明每次发送数据的长度
4. Netty的半包读写
实际在Netty中提供了很多的流数据的编解码器,如LineBasedFrameDecoder(以\r或\r\n作为换行分隔)、DelimiterBasedFrameDecoder(指定分隔符)、FixedLengthFrameDecoder(固定长度分割)等、还可以自定义消息类型,包括消息头和消息体,接收的时候可以根据消息体大小读取消息
5. Netty对象编解码
当进行远程跨进程服务调用时,需要把传输的java对象编码为字节数组,远程读取到字节数组时,在将其解码为发送时的java对象,这被称为java对象的编解码,以下为两种常见编解码方式:
1. java序列化是编解码技术的一种,java序列化的目的有网络传输和对象持久化,但是java序列化的劣势有:无法跨语言;序列化后码流过大;序列化性能低
2. google protobuf是一个业界主流的编解码框架,优点有:结构化数据存储格式(XML、JSON等)、高效的编解码性能、平台和语言无关、支持不同协议版本向前兼容扩展性高
6. Netty多协议应用
- TCP协议实现群聊系统
- HTTP协议
- WebSocket协议
- UDP协议