从Java NIO socketchannel读取字节,直到达到标记

时间:2015-07-17 17:47:16

标签: java sockets nio bytebuffer

我正在寻找一种使用Java NIO从套接字通道读取字节的有效方法。任务很简单,我有一个解决方案,但我正在寻找一种更清洁,更有效的方法来解决这个问题。这是场景:

  1. 从套接字通道中读取数据
  2. 此数据是UTF-8编码的字符串
  3. 每一行都以\ r \ n结束,前面的长度是未知的
  4. 读完每一行后,我想对消息做一些事情
  5. 我的解决方案读取每个字节的数据字节,并将每个字节与我的标记进行比较(在UTF-8代码页中的值为10)。这是代码:

    ByteBuffer res = ByteBuffer.allocate(512);
    boolean completed = false;
    try {
        while (true) {
            ByteBuffer tmp = ByteBuffer.allocate(1);
            if(soc.read(tmp) == -1) {
                 break;
            }
    
            // set marker back to index 0
            tmp.rewind();
            byte cur = tmp.get();
            res.put(cur);
    
            // have we read newline?
            if (cur == 10) {
                doSomething(res);
                res.clear();
            }
        }
    
    } catch(Exception ex) {
         handle(ex);
    }
    

    即使这样做,也可能有更好的方法,每次迭代后不需要每字节比较。

    感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

我这样做的方法是尽可能多地读取,例如32 KB,一旦你读完了它,你就将数据逐字节地复制到另一个缓冲区,例如:一个StringBuilder。如果上次读取时缓冲区中仍有数据,则可以继续使用缓冲区,直到它全部消耗完为止,此时您将读取更多数据。

注意:每次系统调用都很昂贵。它可能需要2-5微秒。除非你打电话数百万次,否则这听起来并不多,并且会增加读取1 MB的秒数。

答案 1 :(得分:0)

这是我最终解决方案的代码。

ByteBuffer res = ByteBuffer.allocate(maxByte);
while (true) {
    ByteBuffer tmp = ByteBuffer.allocate(maxByte);

    int bytesRead = clientSocket.read(tmp);
    if (bytesRead == -1) {
        break;
    }

    // rewind ByteBuffer to get it back to start
    tmp.rewind();

    for (int i = 0; i < bytesRead; i++) {
        byte cur = tmp.get(i);
        res.put(cur);
        if (cur == marker) {
            processMessage(res);
            res = ByteBuffer.allocate(maxByte);
        }
    }

    // reached end of message, break loop
    if (bytesRead < tmpSize) {
        break;
    }
}