粘包
由于TCP协议设计的原因,如果数据量少的话,则会整合多个数据包,然后再一起发送。如下所示,
我们使用一个Socket Client循环发送数据到服务端中,可以看到服务端只接收到一次数据
try {
Socket socket = new Socket("127.0.0.1", 9092);
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
for (int i = 0; i < 100; i++) {
System.out.println("run..");
out.writeUTF("这是第 " + (i+1) + " 次发送的数据");
}
out.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
服务端handler接收并解析数据:
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("接收数据:" + msg);
for (Channel channel : sessionSet) {
if (channel == ctx.channel()) {
channel.writeAndFlush("[自己]:" + msg);
} else {
channel.writeAndFlush("[客户端]:" + msg);
}
}
super.channelRead(ctx, msg);
}
方案1:
如果客户端发送的数据是固定的,服务端可以直接固定读取n个字符串作为一次来使用,Netty在pipline中提供了FixedLengthFrameDecoder
类来设置服务端每次读取多少个字节。
.childHandler(new ChannelInitializer<SocketChannel>() { // (4)
@Override
public void initChannel(SocketChannel ch) throws Exception {
// 每次读取4个字节
ch.pipeline().addLast(new FixedLengthFrameDecoder(4));
ch.pipeline().addLast("decoder", new StringDecoder());
ch.pipeline().addLast("encoder", new StringEncoder( ));
ch.pipeline().addLast(new DiscardServerHandler());
}
})
客户端每次都会发送test字符串,而test字符串占用4个字节长度,我们只要每次固定读取客户端发送来的数据即可,运行如下:
缺点: 无法保证每次客户端发送古来的数据都是固定长度的。
方案2:
采用分隔符的方式来进行截取,例如客户端结尾以下划线分割来标识,服务端只要截取下划线之前的数据即可,这样做的弊端是,客户端发数据就不能发送带下划线的数据了。
public void initChannel(SocketChannel ch) throws Exception {
// 解码最大长度为1024个字节,以下划线结尾
ch.pipeline().addLast(new DelimiterBasedFrameDecoder(1024, Unpooled.copiedBuffer("_".getBytes())));
ch.pipeline().addLast("decoder", new StringDecoder());
ch.pipeline().addLast("encoder", new StringEncoder( ));
ch.pipeline().addLast(new DiscardServerHandler());
}
执行结果如下:
方式3:
利用私有协议来解决粘包的问题,就像HTTP协议一样,将每部分代表特定的含义,比如我们将客户端发过来的信息的前四位代表客户端发送数据的长度,客户端发送数据不满4位是前几位补0,如下所示:
虽然道路是曲折的,但前途是光明的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律