目录
一、TCP的粘包和拆包
TCP协议数据传输是一个无界的数据流,而我们的请求数据确有多有少,所以会出现一次请求数据过多在TCP传输过程中会发送两个包 这种现象称之为拆包,同理粘包是多个请求作为一个TCP数据包传输给服务端。
如下例子:客户端发送两个请求
产生的原因
- 应用程序write字节大小 大于TCP发送缓存区大小
- TCP请求数据大于MSS的设置(MSS是TCP报文负载的最大长度),需要进行TCP分段发送。
那么怎么解决TCP的粘包和拆包的呢?
底层的TCP无法理解上层业务数据,所以在底层无法保证数据不被拆分或者重组,只能通过上层协议来进行处理,如下常用的几种方式
-
消息定长,不足的空位补充
-
消息之间添加边界,比如特殊字符
-
消息使用消息头,头部包含消息的字段长度。
-
使用更复杂的应用协议。
二、复现粘包、拆包问题
2.1、目录结构
下面我们来看看netty例子出现的粘包拆包(同时也是netty使用的例子学习)gitee地址:[netty学习项目](https://gitee.com/xieqx_79/netty-study.git)
module: netty-one
项目结构如下:
相关类说明
- NettyServer: netty服务端
- NettyServerHandler netty服务端读写消息处理器
- NettyClient: netty客户端
- NettyClientHandler netty客户端读写消息处理器
2.2、netty服务端
NettyServer
public class NettyServer extends ChannelInitializer {
public void start(Integer port){
//客户端连接NIO线程组
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
//用户处理读写请求的NIO线程组
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
//NIO服务启动辅助类
ServerBootstrap bootstrap = new ServerBootstrap();
//添加线程池组 添加两个线程池组(一个线程池组用于处理客户端连接,一个线程池组用户处理读写消息)
bootstrap.group(bossGroup,workerGroup)
//添加处理读写的通道
.channel(NioServerSocketChannel.class)
//设置服务端TCP参数 SO_BACKLOG表示和该服务端连接的客户端最大数量
.option(ChannelOption.SO_BACKLOG,1024)
//添加相关处理器(最终组成处理器链对请求进行处理)通过ChannelPipeline添加ChannelHandler
.childHandler(this);
try {
//绑定端口
ChannelFuture sync = bootstrap.bind(port).sync();
//服务监听端口关闭
sync.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
//关闭线程组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
/**
*初始化 为Channel通道的添加相关处理器 处理网络I/O事件
*/
@Override
protected void initChannel(Channel channel) throws Exception {