消息粘包 和 消息不完整 问题

2022-03-30  本文已影响0人  Aska小强

消息粘包 和 消息不完整 问题

消息粘包 和 消息不完整问题 其实都是应用层会带来的问题,和TCP 没关系,TCP 是能够保证消息的顺序 和 完整性的

本篇只是简单说明一下 什么是 消息粘包 和 消息不完整问题

image-20220330104603542

1.复现消息粘包 和 消息不完成 问题

先来看看 出现了什么问题导致 需要去处理 消息粘包 和 消息完整 问题 ,前面通过NIO改造了聊天室的案例中,我们开复现一下 消息粘包 和 消息不完整

1.1 复现 消息粘包问题

Client端发送多条数据

代码还是原来的Client端代码 ,只是在发送数据的时候 一次性发了100条

public static void connectServer(ServerInfo serverInfo) {
        try {
            // 开启 tcp 连接
            socket = new Socket(Inet4Address.getByName(serverInfo.getIp()), serverInfo.getPort());
            // 开启 线程 异步 读取 server message
            clientReadHandler =
                    new ClientReadHandler(socket.getInputStream(), ClientConnectTcp::close);
            clientReadHandler.start();
            // 监听 键盘写入 system.in
            systemInReader = new BufferedReader(new InputStreamReader(System.in));
            clientWriteHandler = new ClientWriteHandler(socket.getOutputStream());
            do {
                String message = systemInReader.readLine();
                // 异步发送 到 server
                if (message != null) {
                     //把读取到的message 发送100次 并且后面添加上i标识
                    for (int i = 0; i < 100; i++) {
                        clientWriteHandler.sendMsg(message + ":" + i);
                    }
                }
                if (CommonConstants.BYE_FLAG.equals(message)) {
                    close();
                }
            } while (!doReadFlag);
        } catch (IOException e) {
            log.error("【建立tcp 连接异常:{}】", e.getMessage());
        } finally {
            close();
        }
    }

Server端 接受到的消息

可以看到 出现了严重的粘包问题,原本我们希望 消息是一条一条处理,如下:

receiveAsync message:abcdefg:0

receiveAsync message:abcdefg:1

receiveAsync message:abcdefg:2

10:12:21.721 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abcdefg:0
abcdefg:1
abcdefg:2
abcdefg:3
abcdefg:4
abcdefg:5
abcdefg:6
abcdefg:7
abcdefg:8
abcdefg:9
abcdefg:10
abcdefg:11
abcdefg:12
abcdefg:13
abcdefg:14
abcdefg:15
abcdefg:16
abcdefg:17
abcdefg:18
abcdefg:19
abcdefg:20
abcdefg:21
abcdefg:22
abcdefg:23
a
10:12:21.722 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cdefg:24
abcdefg:25
abcdefg:26

1.2 复现 消息不完整问题

修改Server 服务器端的 IoArgs 的 ByteBuffer的 缓冲区大小

@Slf4j
@Data
public class IoArgs {
  //缓冲区大小 从 256个字节  改成 4 个字节
  private ByteBuffer byteBuffer = ByteBuffer.allocate(4);
  其他代码省略...
}  

Client客户端还是如下 发送100条数据

do {
       String message = systemInReader.readLine();
       // 异步发送 到 server
       if (message != null) {
           for (int i = 0; i < 100; i++) {
              clientWriteHandler.sendMsg(message + ":" + i);
          }
       }
       if (CommonConstants.BYE_FLAG.equals(message)) {
           close();
       }
 } while (!doReadFlag);

Server端 接受到的消息

可以看到 原本一条消息 abcdefg 被拆开成了 很多子消息了。。出现了 严重的 消息不完整问题

10:19:38.754 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abc
10:19:38.754 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg
10:19:38.755 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:0
a
10:19:38.755 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cde
10:19:38.756 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:g:1
10:19:38.756 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abc
10:19:38.756 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg
10:19:38.756 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:2
a
10:19:38.756 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cde
10:19:38.757 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:g:3
10:19:38.757 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abc
10:19:38.757 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg
10:19:38.757 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:4

2. 消息粘包 和 消息不完成 问题概述

在socket网络编程中,都是端到端通信,由客户端端口+服务端端口+客户端IP+服务端IP+传输协议组成的五元组可以明确的标识一条连接。在TCP的socket编程中,发送端和接收端都有成对的socket。发送端为了将多个发往接收端的包,更加高效的的发给接收端,于是采用了优化算法(Nagle算法)将多次间隔较小、数据量较小的数据,合并成一个数据量大的数据块,然后进行封包。那么这样一来,接收端就必须使用高效科学的拆包机制来分辨这些数据。

2.1 什么是TCP粘包问题?

TCP粘包就是指发送方发送的若干包数据到达接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾,出现粘包的原因是多方面的,可能是来自发送方,也可能是来自接收方。

2.2 造成TCP粘包的原因

2.3 如何处理粘包现象?

总结

本篇简单概述了一下 什么是 消息粘包 和 消息不完整问题,并且通过代码 复现了一下出现的问题,那么具体的处理粘包等问题,后面再写,核心思想就是 通过读取包头获取要读取的数据包的长度,然后根据长度去读取后面的数据,不够就先缓存 等待下一个包来,足够了长度就丢给上层处理,既解决了 消息粘包 也能解决消息不完整问题,具体代码演示 下一篇再述

欢迎大家访问 个人博客 Johnny小屋

上一篇 下一篇

猜你喜欢

热点阅读