免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

消息粘包 和 消息不完整 问题-元一软件

消息粘包 和 消息不完整 问题-元一软件 消息粘包 和 消息不完整 问题消息粘包 和 消息不完整问题 其实都是应用层会带来的问题和TCP 没关系TCP 是能够保证消息的顺序 和 完整性的本篇只是简单说明一下 什么是 消息粘包 和 消息不完整问题1.复现消息粘包 和 消息不完成 问题先来看看 出现了什么问题导致 需要去处理 消息粘包 和 消息完整 问题 前面通过NIO改造了聊天室的案例中我们开复现一下 消息粘包 和 消息不完整1.1 复现 消息粘包问题Client端发送多条数据代码还是原来的Client端代码 只是在发送数据的时候 一次性发了100条public static void connectServer(ServerInfo serverInfo){try{// 开启 tcp 连接 socketnew Socket(Inet4Address.getByName(serverInfo.getIp()), serverInfo.getPort());// 开启 线程 异步 读取 server message clientReadHandlernew ClientReadHandler(socket.getInputStream(), ClientConnectTcp::close);clientReadHandler.start();// 监听 键盘写入 system.in systemInReadernew BufferedReader(new InputStreamReader(System.in));clientWriteHandlernew ClientWriteHandler(socket.getOutputStream());do{String messagesystemInReader.readLine();// 异步发送 到 serverif(message!null){//把读取到的message 发送100次 并且后面添加上i标识for(int i0;i100;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:0receiveAsync message:abcdefg:1receiveAsync message:abcdefg:210: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 a10:12:21.722[read-io-executors2]INFO com.johnny.chatroom.lib.nio.Connector - receiveAsync message:cdefg:24 abcdefg:25 abcdefg:261.2 复现 消息不完整问题修改Server 服务器端的 IoArgs 的 ByteBuffer的 缓冲区大小Slf4j Data public class IoArgs{//缓冲区大小 从256个字节 改成4个字节 private ByteBuffer byteBufferByteBuffer.allocate(4);其他代码省略...}Client客户端还是如下 发送100条数据do{String messagesystemInReader.readLine();// 异步发送 到 serverif(message!null){for(int i0;i100;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:0 a10: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:2 a10: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:42. 消息粘包 和 消息不完成 问题概述在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.以指定字符串为包的结束标志 如换行符 \n3.包头 包体格式 这种格式的包一般分为两部分即包头和包体包头是固定大小的且包头中必须含有一个字段来说明接下来的包体有多大。总结
返回列表