NIO 缓冲区 ByteBuffer 之黏包和半包

 

/**
 * 黏包、半包
 */
private static void buffExample2() {
    /*
    网络上传输多条数据给服务器,数据之间使用 \n 分隔。
    但由于某种原因(多条数据合并发送会快)这些数据在接收时,被进行了重新组合,例如3条原始数据:
        Hello world!\n
        I'm Lihua.\n
        How are you?\n
     变成了2个 ByteBuffer,一个叫黏包,一个叫半包:
        Hello world!\nI'm Lihua.\nHow a
        re you?\n

     如何使用代码将错乱的数据恢复成原来使用 \n 分割的样子
     */
    // 模拟处理黏包、半包现象
    ByteBuffer buf1 = ByteBuffer.allocate(50); // 接受到网络传输第一条消息
    buf1.put("Hello world!\nI'm Lihua.\nHow a".getBytes(StandardCharsets.UTF_8));
    System.out.println("第一次调用:");
    msgSplit(buf1); // 调用处理方法
    buf1.put("re you?\n".getBytes(StandardCharsets.UTF_8)); // 接受到网络传输第二条消息
    System.out.println("第二次调用:");
    msgSplit(buf1); // 调用处理方法

}

private static void msgSplit(ByteBuffer buff) {
    buff.flip(); // 切换成读模式,为下面的读取字符做准备
    for (int i = 0; i < buff.limit(); i++) {
        if (buff.get(i) == '\n') { // 判断 \n 所在位置
            // 计算将要截取字符串的长度,包含 \n 符号在内
            int len = i + 1 - buff.position(); // buff.position() 指针的位置
            System.out.println("position:" + buff.position() + ",limit:" + buff.limit() + ",len:" + len);
            ByteBuffer readBuff = ByteBuffer.allocate(len);
            for (int j = 0; j < len; j++) {
                readBuff.put(buff.get());
            }
            readBuff.flip();
            System.out.println("读取到的消息:" + StandardCharsets.UTF_8.decode(readBuff));
        }
    }
    System.out.println("切换成写模式!");
    buff.compact(); // 切换成写模式,为后面消息写入做准备
}

 

上一篇:想找工作的你还不看这份资料就晚了!面试篇


下一篇:io系列浅谈