一、前言

Netty 是一个可以快速开发网络应用程序的 NIO 框架,它大大简化了 TCP 或者 UDP 服务器的网络编程。Netty 的简易和快速开发并不意味着由它开发的程序将失去可维护性或者存在性能问题,它的设计参考了许多协议的实现,比如 FTP、SMTP、HTTP 和各种二进制和基于文本的传统协议,因此 Netty 成功的实现了兼顾快速开发、性能、稳定性、灵活性为一体,不需要为了考虑一方面原因而妥协其他方面。Netty 的应用还是比较广泛的,比如阿里巴巴开源的 Dubbo 和 Sofa-Bolt 框架底层网络通讯都是基于 Netty 来实现的。

本 Chat 主要讲解 Netty 中的粘包与半包问题,主要包含下面内容:

什么是粘包与半包问题,为何会出现,如何避免?

如何使用包定长 FixedLengthFrameDecoder 解决粘包与半包问题?原理是什么?

如何使用包分隔符 DelimiterBasedFrameDecoder 解决粘包与半包问题?原理是什么?

Dubbo 在使用 Netty 作为网络通讯时候是如何避免粘包与半包问题?

Netty 框架本身存在粘包半包问题?什么时候需要考虑粘包与半包问题?

二、粘包与半包问题

大家都知道在客户端与服务端进行网络通信时候,客户端会通过socket 把需要发送的内容进行序列化为二进制流后发送出去,然后二进制流通过网络流向服务器端,服务端接受到该请求后会解析该请求包,然后反序列化后对请求进行处理。这看似是一个很简单的过程,但是细细想来却会发现没有那么简单。

如上图首先在客户端发送数据时,实际是把数据写入到了 TCP 发送缓存里面的,如果发送的包的大小比 TCP 发送缓存的容量大,那么这个数据包就会被分成多个包,通过 socket 多次发送到服务端。而服务端获取数据是从接受缓存里面获取的,假设服务端第一次从接受缓存里面获取的数据是整个包的一部分,这时候就产生了半包现象,半包不是说只收到了全包的一半,是说收到了全包的一部分。

服务器读取到半包数据后,会对读取的二进制流进行解析,一般的会把二进制流反序列化为对象,这里服务器由于只读取了客户端序列化对象后的一部分,所以反序列会报错。

同理如果发送的数据包大小比 TCP 发送缓存容量小,并且假设 TCP 缓存可以存放多个包,那么客户端和服务端的一次通信就可能传递了多个包,这时候服务端从接受缓存就可能一下读取了多个包,这时候就出现了粘包现象,由于服务端从接受缓存获取的二进制流是多个对象转换来的,所以在后续的反序列化时候肯定也会出错。

其实出现粘包和半包的原因是 TCP 层不知道上层业务的包的概念,它只是简单的传递流,所以需要上层应用层协议来识别读取的数据是不是一个完整的包。

那么如何避免粘包与半包的出现?

比较常见方案是在应用层设计协议时候把协议包分为 header 和 body 两部分,header 里面记录 body 长度。当服务端从接受缓冲区读取数据后,如果发现数据大小小于包的长度则说明出现了半包,这时候就回退读取缓存的指针,等待下次读事件到来的时候再次测试。如果发现包长度大于了包长度则看如果长度是包大小整数倍则说明了出现了粘包,则循环读取多个包,否者就是出现了多个整包+半包,这时候读取整数个包然后回退半包的指针。如下图是 Dubbo 协议帧个数:

其中 header 格式如下:

可知 header 记录 body 长度。

还有一种方式是在多个包之间添加分隔符,使用分隔符来判断一个包的结束

可知这种方式时候每个包大小可以不固定,当服务器端读取时候每次遇到分隔符就知道当前包结束了。

还有一种是包定长,就是每个包大小固定长度。

可知这种方式每个包的大小必须一致。

三、Netty 与粘包半包

首先我们来看一个简单的 Netty 搭建的客户与服务端通信的例子,这个例子比较简单,需要详细讲解的童鞋可以移步:

3.1 客户端代码

public final class NettyClient {

static final String HOST = System.getProperty("host", "127.0.0.1");

static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));

public static void main(String[] args) throws Exception {

//1.1 创建Reactor线程池

EventLoopGroup group = new NioEventLoopGroup();

try {//1.2 创建启动类Bootstrap实例,用来设置客户端相关参数

Bootstrap b = new Bootstrap();

b.group(group)//1.2.1设置线程池

.channel(NioSocketChannel.class)//1.2.2指定用于创建客户端NIO通道的Class对象

.option(ChannelOption.TCP_NODELAY, true)//1.2.3设置客户端套接字参数

.handler(new ChannelInitializer() {//1.2.4设置用户自定义handler

@Override

public void initChannel(SocketChannel ch) throws Exception {

ChannelPipeline p = ch.pipeline();

p.addLast(new NettyClientHandler());

}

});

// 1.3启动链接

ChannelFuture f = b.connect(HOST, PORT).sync();

//1.4 同步等待链接断开

f.channel().closeFuture().sync();

} finally {

// 1.5优雅关闭线程池

group.shutdownGracefully();

}

}

}

其中自定义 NettyClientHandler 的代码如下:

netty半包粘包 处理_Java NIO 框架 Netty 之美:粘包与半包问题相关推荐

  1. java netty 教程_Java NIO框架Netty教程(十六)

    该图是OneCoder通过阅读Netty源码,逐渐记录下来的.基本可以说明Netty服务的启动流程.这里在具体讲解一下. 首先说明,我们这次顺利的流程是基于NioSocketServer的.也就是基于 ...

  2. java框架白话_Java NIO框架Netty教程(二) 白话概念

    "Hello World"的代码固然简单,不过其中的几个重要概念(类)和 Netty的工作原理还是需要简单明确一下,至少知道其是负责什.方便自己以后更灵活的使用和扩展. 声明,笔者 ...

  3. java netty教程_Java NIO框架Netty教程(一) – Hello Netty

    先啰嗦两句,如果你还不知道Netty是做什么的能做什么.那可以先简单的搜索了解一下.我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序.具体能做什么,各位可以尽量发挥想象.技术,是 ...

  4. java nio框架netty教程_Java NIO框架Netty教程(一) – Hello Netty

    先啰嗦两句,如果你还不知道Netty是做什么的能做什么.那可以先简单的搜索了解一下.我只能说Netty是一个NIO的框架,可以用于开发分布式的Java程序.具体能做什么,各位可以尽量发挥想象.技术,是 ...

  5. Java NIO 框架 Netty 之美:粘包与半包问题

    Netty 是一个可以快速开发网络应用程序的 NIO 框架,它大大简化了 TCP 或者 UDP 服务器的网络编程.Netty 的简易和快速开发并不意味着由它开发的程序将失去可维护性或者存在性能问题,它 ...

  6. 【Java进阶营】Java异步NIO框架Netty实现高性能高并发

    1. 背景 1.1. 惊人的性能数据 最近一个圈内朋友通过私信告诉我,通过使用Netty4 + Thrift压缩二进制编解码技术,他们实现了10W TPS(1K的复杂POJO对象)的跨节点远程服务调用 ...

  7. netty高性能编程基础(BIO、NIO、Netty、源码、使用netty实现dubbo RPC)

    文章目录 第1章Netty介绍和应用场景 1.1Netty介绍 1.2应用场景 第2章Java BIO编程 2.1 IO模型 2.2BIO.NIO.AIO适用场景分析 2.3JavaBIO基本介绍 第 ...

  8. java netty 教程,Java NIO框架Netty教程(十七) - Netty4 Hello world

    最近很多人问我有没有Netty4的Hello World样例,很早之前知道Netty要出4,当时只知道4的包名完全边了,因为Netty从JBoss中独立出来了,并采用了新的netty.io的域名,但是 ...

  9. 高性能NIO框架Netty入门篇

    http://cxytiandi.com/blog/detail/17345 Netty介绍 Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具 ...

最新文章

  1. ExtJS4.x 开发环境搭建
  2. mysql之DDL操作--数据库
  3. LightOJ - 1409 Rent a Car(最小费用最大流)
  4. tomcat安全机制j_security_check(简单版)
  5. 3.3.10 动态SQL
  6. mount 挂载光盘
  7. C语言case字句有什么作用,switch case 语句的使用规则
  8. 程序简单教程:飞秋官方下载
  9. springboot整合jwt_springBoot整合JWT使用
  10. [jquery] 删除文章的时候弹出确认窗口
  11. C++基础:第四章 数组、vector和字符串
  12. 通过微信小程序看趋势
  13. 小米路由器(R2D)开发版-固件分析
  14. AI再造一个“李佳琦”,难嘛?
  15. Mysql创建事件执行任务
  16. linux无线usb网卡,linux usb 无线网卡
  17. HackerRank - C语言 - Introduction - Playing With Characters
  18. Perl 正则表达式 模式匹配
  19. 为将来而记下的过去——扭曲的爱,病态的教育
  20. MatLab中多项式

热门文章

  1. 计算机械效率的公式怎么读,机械效率的计算公式
  2. [34]如何设置PPT中的演讲者模式
  3. 20189216 《网络攻防技术》第六周作业
  4. 科技爱好者周刊(第 185 期):美国宪法拍卖,一个区块链案例
  5. 智能安防--人工智能在安防行业的应用
  6. Java网络斗地主小程序
  7. 计算机网络 P32 IPv4 2-7 p36
  8. 制约软件产业发展的三要素
  9. MacBook Pro使用入门
  10. ie下,首页打开页面非常慢