音讯粘包 和 音讯不残缺 问题

音讯粘包 和 音讯不残缺问题 其实都是应用层会带来的问题,和TCP 没关系,TCP 是可能保障音讯的程序 和 完整性的

本篇只是简略阐明一下 什么是 音讯粘包 和 音讯不残缺问题

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

1.2 复现 音讯不残缺问题

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

@Slf4j@Datapublic 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:abc10:19:38.754 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg10:19:38.755 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:0a10:19:38.755 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cde10:19:38.756 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:g:110:19:38.756 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abc10:19:38.756 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg10:19:38.756 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:2a10:19:38.756 [read-io-executors1] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cde10:19:38.757 [read-io-executors2] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:g:310:19:38.757 [read-io-executors3] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:abc10:19:38.757 [read-io-executors4] INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:efg10: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粘包的起因

  • 发送方起因

    TCP默认应用Nagle算法(次要作用:缩小网络中报文段的数量),而Nagle算法次要做两件事:

    只有上一个分组失去确认,才会发送下一个分组
    收集多个小分组,在一个确认到来时一起发送
    Nagle算法造成了发送方可能会呈现粘包问题

  • 接管方起因

    TCP接管到数据包时,并不会马上交到应用层进行解决,或者说应用层并不会立刻解决。实际上,TCP将接管到的数据包保留在接管缓存里,而后应用程序被动从缓存读取收到的分组。这样一来,如果TCP接管数据包到缓存的速度大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就有可能读取到多个首尾相接粘到一起的包。

  • 什么时候须要解决粘包景象?

    如果发送方发送的多组数据原本就是同一块数据的不同局部,比如说一个文件被分成多个局部发送,这时当然不须要解决粘包景象
    如果多个分组毫不相干,甚至是并列关系,那么这个时候就肯定要解决粘包景象了

2.3 如何解决粘包景象?

  • 发送方

    对于发送方造成的粘包问题,能够通过敞开Nagle算法来解决,应用TCP_NODELAY选项来敞开算法

  • 接管方

    接管方没有方法来解决粘包景象,只能将问题交给应用层来解决

  • 应用层

    应用层的解决办法简略可行,不仅能解决接管方的粘包问题,还能够解决发送方的粘包问题。

    1.固定包长度的数据包

    2.以指定字符(串)为包的完结标记 如换行符 \n

    3.包头 + 包体格局 这种格局的包个别分为两局部,即包头和包体,包头是固定大小的,且包头中必须含有一个字段来阐明接下来的包体有多大。

总结

本篇简略概述了一下 什么是 音讯粘包 和 音讯不残缺问题,并且通过代码 复现了一下呈现的问题,那么具体的解决粘包等问题,前面再写,核心思想就是 通过读取包头获取要读取的数据包的长度,而后依据长度去读取前面的数据,不够就先缓存 期待下一个包来,足够了长度就丢给下层解决,既解决了 音讯粘包 也能解决音讯不残缺问题,具体代码演示 下一篇再述

欢送大家拜访 集体博客 Johnny小屋