TCP粘包/拆包问题的解决之道

2018/02 27 14:02

1.TCP粘包/拆包

TCP地城并不了解上层业务数据的具体含义,它会根据TCP缓冲区的实际情况进行包的拆分,所以在业务上认为,一个完整的包可能会被TCP拆分成多个包进行发送,也有可能把多个小的包封装成一个大的数据包发送,这就是所谓的TCP的粘包和拆包.

TCP粘包/拆包发生的原因:

(1)应用程序write写入的字节大小大于套接口发送缓冲区大小

(2)进行MSS大小的TCP分段

(3)以太网帧的payload大于MTU进行IP分片

粘包问题的解决策略

(1)消息定长

(2)在包尾增加回车换行符进行分割,例如FTP协议

(3) 将消息分为消息头和消息体,消息头中包含表示消息体的总长度的字段,通常涉及思路为消息头的第一个字段使用int32来表示消息的总长度;

(4)更为负责的应用层协议

2.未考虑TCP粘包导致功能异常的案例


package cn.guangboyuan.now03;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
* Created by RedAnts on 2018/2/27.
*/
public class TimeClient {
public void connect(int port, String host) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY, true)
.handler(new ChannelInitializer() {
@Override
public void initChannel(SocketChannel socketChannel) throws Exception {
socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));
socketChannel.pipeline().addLast(new StringDecoder());
socketChannel.pipeline().addLast(new TimeClientHandler());
}
});
//发起异步连接操作
ChannelFuture f = b.connect(host, port).sync();
//等待客户端链路关闭
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}

public static void main(String[] args)throws Exception{
int port = 8080;
if(args != null & args.length> 0){
try {
port = Integer.valueOf(args[0]);
}catch (NumberFormatException e){
//采用默认值
}
}
new TimeClient().connect(port,"127.0.0.1");
}
}


 

--转载请注明: https://www.guangboyuan.cn/tcp%e7%b2%98%e5%8c%85%e6%8b%86%e5%8c%85%e9%97%ae%e9%a2%98%e7%9a%84%e8%a7%a3%e5%86%b3%e4%b9%8b%e9%81%93/

发表回复

(必填)