概念
粘包
当用户消息通过 TCP 协议传输时,消息可能会被操作系统分组成多个的 TCP 报文,也就是一个完整的用户消息被拆分成多个 TCP 报文进行传输。这时,接收方的程序如果不知道发送方发送的消息的长度,也就是不知道消息的边界时,是无法读出一个有效的用户消息的,因为用户消息被拆分成多个 TCP 报文后,并不能像 UDP 那样,一个 UDP 报文就能代表一个完整的用户消息。发送端使用send 函数 后、数据并没有真正从网络上真正发出,而是从应用程序拷贝到了操作系统的应用程序栈中,至于什么时候发送,取决于发送窗口、拥塞窗口以及当前发送缓冲区的大小等条件。 所以不能认为 TCP 发送数据 会被作为一个整体发送出去。
粘包 : 两个消息被分到同一个TCP 报文。
半包 : 主要因素是由于缓冲区的因素,只能发送一半的数据。
解决 (使用换行符作为消息的边界)
public class StickPackage {
public static void main(String[] args) {
ByteBuffer allocate = ByteBuffer.allocate(32);
allocate.put("hello,world\nI'm xiaolin\nHo".getBytes(StandardCharsets.UTF_8));
split(allocate);
allocate.put("w are you\n".getBytes(StandardCharsets.UTF_8));
split(allocate);
}
private static void split(ByteBuffer allocate) {
// byteBuffer 切换至读模式
allocate.flip();
for (int i = 0 ; i < allocate.limit(); i ++) {
byte b = allocate.get(i);
if (b == '\n') {
// 存入新的 ByteBuffer
int len = i - allocate.position() + 1;
ByteBuffer target = ByteBuffer.allocate(len);
for (int j = 0; j < len; j++) {
//相对 获取 方法。读取该缓冲区当前位置的字节,然后增加位置。
target.put(allocate.get());
}
// 拆分
System.out.println("postion "+ allocate.position());
debugAll(target);
}
}
// 压缩已读,并切换到写模式
allocate.compact();
}
}