2023图灵Java架构师第6期学习笔记-怎么解决网络粘包?

Published on with 0 views and 0 comments

【微信642620018,获取图灵学院Java架构师23456期vip全套课程】

网络粘包是指在TCP协议下,发送方发出的若干数据包,在接收方收到时,可能不按发送方发送的方式进行处理,导致接收方无法正常解析数据包的情况。这是一个常见的问题,发生原因主要是TCP接收缓冲区较小,处理不及时,导致多个数据包被合并成一个大的数据块。

在Java中,可以通过以下方法解决网络粘包问题:

1.通过增加消息头来解决:可以在消息头中包含消息的长度信息,在接收端接收到数据包时根据消息头中的长度信息进行分包。

//发送端
String msg = ...; // 待发送的消息
// 在消息前增加4字节的消息长度信息
byte[] header = ByteBuffer.allocate(4).putInt(msg.getBytes().length).array();
byte[] body = msg.getBytes();
byte[] data = new byte[header.length + body.length];
System.arraycopy(header, 0, data, 0, header.length);
System.arraycopy(body, 0, data, header.length, body.length);
outputStream.write(data);

// 接收端
InputStream inputStream = ...; //输入流
byte[] header = new byte[4];
inputStream.read(header); //读取长度信息
int length = ByteBuffer.wrap(header).getInt(); // 解析长度信息
byte[] body = new byte[length];
inputStream.read(body); // 读取数据
String msg = new String(body);

2.通过边读取边处理的方式解决:在接收端通过开启多线程边读取边处理的方式来解决粘包问题,每次读取指定字节长度的数据包,然后进行数据包的解析和处理。

// 开启多线程,边读取边处理
new Thread(() -> {
    byte[] buffer = new byte[1024];
    int len;
    while ((len = inputStream.read(buffer)) != -1) {
        // 处理接收到的数据,每次读取指定长度的数据包
        String msg = new String(buffer, 0, len);
        // TODO: 处理消息
    }
}).start();

3.通过Netty的FixedLengthFrameDecoder来解决:Netty是一个基于NIO的客户端/服务器框架,它提供了很多的高性能网络编程解决方案。其中FixedLengthFrameDecoder是一个解决TCP粘包问题的解决方案。使用FixedLengthFrameDecoder,接收端可以按照指定长度进行分包处理。

// 创建一个FixedLengthFrameDecoder,每次读取20个字节长度的数据包
ByteBuf delimiter = Unpooled.copiedBuffer("20".getBytes());
ByteToMessageDecoder decoder = new FixedLengthFrameDecoder(20);
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(decoder);
pipeline.addLast(...)

4.通过Netty的DelimiterBasedFrameDecoder来解决:DelimiterBasedFrameDecoder是另一种解决TCP粘包问题的解决方案。使用DelimiterBasedFrameDecoder,可以通过特定的分隔符来将数据包进行拆分。

// 创建一个DelimiterBasedFrameDecoder,以"\r\n"为分隔符进行数据拆分
ByteBuf delimiter = Unpooled.copiedBuffer("\r\n".getBytes());
ByteToMessageDecoder decoder = new DelimiterBasedFrameDecoder(4096, delimiter);
ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast(decoder);
pipeline.addLast(...)

在选择解决方案时,需要根据实际情况和需求进行选择。同时,需要注意异常情况的处理,避免出现空指针异常等问题。

参考链接:
https://www.mufc360.cn/archives/tl10251
https://www.cr7mufc520.cn/archives/tl10251
https://www.vx642620018.top/articles/2023/06/09/1686279286789.html


标题:2023图灵Java架构师第6期学习笔记-怎么解决网络粘包?
作者:vx1039576978
地址:https://vx642620018.top/articles/2023/06/09/1686279286789.html