一、示例
互联网的发展使得设备之间的网络通讯必不可少,通常用的最多的传输层协议就是TCP协议。有如下场景:
有A、B两个节点,A、B建立TCP连接后,A对B说了一百句话。
1、客户端程序
public class SocketClient {
public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1", 8088);
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
for (int i = 0; i < 100; i++) {
os.write("A".getBytes());
}
pw.flush();
pw.close();
os.close();
socket.close();
}
}
2、服务端程序
public class SocketServer {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(8088);
while (true) {
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
int i = 0;
byte[] b = new byte[10];
while (is.read(b) != -1) {
i++;
System.out.println(new String(b));
b = new byte[10];
}
System.out.println("总数读取次数" + i);
is.close();
socket.close();
}
}
}
3、运行结果
总读取次数总是少于100
二、问题
上面所述问题是很常见的场景,建立起一个长连接进行交互,列如RPC、NIO编程等等。
我们希望的结果是,一次交互一次读写,上面实例运行结果少于100次,说明有些数据库包被打包在一起发送,这就引出了今天的话题,TCP粘包拆包。
三、TCP粘包拆包
TCP协议是“流”协议,没有边界,TCP是传输层协议,它并不知道应用层业务数据的真正含义,它会根据TCP缓冲区的具体大小来进行包的划分,一个完整的包可能会被拆分成多个包来传输,也可能多个包会被合并层一个大数据包来传输,这就是粘包和拆包。
四、可能出现的情况
假设Client端向Server端发送A、B两个数据包,可能出现以下情况
1、服务端接收到A、B两个独立的数据包,没有拆包和粘包,这种情况是我们大多数场景下希望的;
2、服务端一次性收到了AB两个包,A、B两包被粘在一起发送过来;
3、A数据包被拆分成A1、A2,服务端先收到A1包,后收到A2和B的合包,这就发生了拆包和粘包两种情况;
4、情况最糟糕的是A、B两包被多次拆分,发送到服务端。
大多数情况下,我们希望一次交互,能拿到交互中传递的完整信息,那么有哪些解决方案解决TCP传输过程中的拆包与粘包问题呢?请关注《TCP粘包拆包二》。
快乐源于分享。
此博客乃作者原创, 转载请注明出处