登录
原创

网络编程的拆包和黏包

发布于 2021-04-29 阅读 54
  • Java
原创

前言

在网络编程中,我们到底在监控用户的输入的时候,往往采用换行符号,作为一次输入的结尾,但是用户发送的数据不可能每次只有一行,这就需要我们对用户的数据进行拆包和分包,假设的用户要输出的数据是

123456
12345678901234567890123
123456
kkkkkk

99999
000000000000000000000
ppppp
0
000000

思路

可以看到,假设我们设置的缓冲区大小是10,那么第一次读取的数据是123456\n123这10个字节的数字,此时,如果第一次读取的数据,已经产生了黏包,需要把\n后面的123给取出,并且不能完全去除,还需要找个地方暂存起来。

接下来是第二轮读取,此时,由于暂存区还有第一次剩下的123占用了3个字节,所以第二次读到的只能是读取到的第二行中的45678907个字符,此时缓冲区中的数据是1234567890,此时显然还没有读取到换行符,此时,需要将这些字符全部另找一个地方存起来,并且,10个字节的缓存区,需要清空,以备下次再读取10个字节的字符,如此循环往复。

代码

package com.cloud;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;

public class TestByteBuffer5 {
    //集中写入
    public static void main(String[] args) {
        //解决思路,有可能第一次读取的是完整的,并且还多余了,
        //第二次发的是完整的,但是是一半
        try (FileChannel channel = new FileInputStream("data3.txt").getChannel()) {
            ByteBuffer buffer = ByteBuffer.allocate(10);
            StringBuilder builder = new StringBuilder();
            while (true) {
                //第一次读取10个字节123456\n123
                int read = channel.read(buffer);
                if (read == -1 && buffer.position()==0) {
                    break;
                }
                StringBuilder line = new StringBuilder();
                //转化为读取模式
                buffer.flip();
                int i = 0;
                while (buffer.hasRemaining()) {
                    byte b = buffer.get();
                    line.append((char) b);
                    if ((char) b == '\n') {
                        //读取到\n之后,应该把buffer给compact一下,把剩余的字符挪到buffer的最前面
                        //遇到\n,把第一行的数据输出
                        if (builder.toString().equals("")){
                            System.out.print(line);
                        } else {

                            System.out.print(builder+line.toString());
                            builder = new StringBuilder();

                        }
                        //此时把剩余的字符挪到buffer的最前面
                        
                        buffer.compact();
                        
                        break;
                    } else {
                        i++;
                        if (i == 10) {
                            //证明这一轮循环当中,并没有碰到换行符号,那么这次的字符应该全部缓存起来
                            builder.append(line);
                            //此时读取了10次,那么应该把buffer清空
                            buffer.clear();
                            break;
                            //那么什么时候把builder输出呢?
                        }
                    }
                }


            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        //每次读取遇到\n,那么就输出一次内容,并且,将剩余的内容,进行重新分配

    }
}

评论区

眉上的汗水,眉下的泪水,你总要选择一样

1

2

0

举报