1、定义
什么是粘包和半包?
粘包:指的是服务端一次接收到了多个数据包,不同的数据包黏在了一起。比如:客户端发送了2句话,一句是Hello,另一句是World,但是服务端收到的是HelloWorld。我们希望服务端收到的是2句话,但是2句话却在一起无法区分开,这就是粘包现象。
半包:指的是数据包不完整,只有一半。比如:客户端发送了一句Hello,但是服务端收到的却是"Hell"和"o",我们希望服务端收到的是一句话,但是服务端收到的却是2句话,这个就是半包现象。
2、原因
为什么会出现粘包和半包的现象呢?
粘包现象原因:
服务端ByteBuffer设置的太大。例如服务端的ByteBuffer设置成了1024个字节,现在客户端发送了2句话,第一句为256个字节,第二句为300个字节,这时,如果服务端处理不及时,那么ByteBuffer完全可以存储这2句话,等服务端再处理的时候,就相当于是一句话了。
半包现象原因:
服务端ByteBuffer设置的太小。例如服务端的ByteBuffer设置了1024个字节,但是客户端发送过来的数据大小为2048个字节,那么此时服务端的ByteBuffer无法一次性存储下,只能先发送1024个字节,这样就会导致半包现象。
3、解决方案
(1)服务端和客户端固定发送数据的大小,但是这样会造成空间的浪费
(2)自定义数据协议,添加数据长度和数据内容,服务端在接收到数据后,解析出本次数据的长度,这样就不会存在上述现象
(3)以特殊字符结尾,比如:'\n',这样就知道数据的具体边界,就能解决上述问题。简单代码示例如下:
public class Test {
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(24);
// 假设已经知道每个消息的结尾都是特殊字符\n
buffer.put("Hello\nWo".getBytes());
send(buffer);
buffer.put("rld\n".getBytes());
send(buffer);
}
public static void send(ByteBuffer byteBuffer) {
// 切换至读模式
byteBuffer.flip();
for(int i = 0; i < byteBuffer.limit(); i++) {
// 查看当前是否是分割符
if(byteBuffer.get(i) == '\n') {
int length = i - byteBuffer.position() + 1;
byte[] bytes = new byte[length];
byteBuffer.get(bytes, 0, length);
System.out.print("收到消息:" + new String(bytes));
}
}
byteBuffer.compact();
}
}
Comments NOTHING