简体   繁体   English

从 Java NIO 套接字通道读取字节,直到到达标记

[英]Read bytes from Java NIO socketchannel until marker is reached

I´m searching for an efficient way to read bytes from a socket channel using Java NIO.我正在寻找一种使用 Java NIO 从套接字通道读取字节的有效方法。 The task is quite easy, I have a solution, though I´m searching for a cleaner and more efficient way to solve this.这个任务很简单,我有一个解决方案,尽管我正在寻找一种更清洁、更有效的方法来解决这个问题。 Here´s the scenario:这是场景:

  1. Data is read from a socket channel从套接字通道读取数据
  2. This data is a UTF-8 encoded string此数据是 UTF-8 编码字符串
  3. Every line is ended by \r\n, the length is unknown up front每行以\r\n结尾,长度未知
  4. After every line read, I want to do something with the message读完每一行后,我想对消息做点什么

My solution reads the data byte per byte and compares every byte to my marker (which is has the value 10 in UTF-8 code pages).我的解决方案按字节读取数据字节并将每个字节与我的标记(在 UTF-8 代码页中的值为 10)进行比较。 Here´s the code:这是代码:

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);
}

Even though this does the job, there might be a better way, that doesn't need those per byte comparisons after every iteration.即使这样做了,也可能有更好的方法,不需要在每次迭代后进行每字节比较。

Thanks for your help!谢谢你的帮助!

The way I would do it is to read as much as is available, such as 32 KB, and once you have read this, you copy the data byte-by-byte to another buffer, eg a StringBuilder. 我这样做的方法是尽可能多地读取,例如32 KB,一旦你读完了它,你就将数据逐字节复制到另一个缓冲区,例如StringBuilder。 If there is data left in the buffer from the last time you read, you can continue using the buffer until it it is all consumed, at which point you read more data. 如果上次读取时缓冲区中仍有数据,则可以继续使用缓冲区,直到它全部消耗完为止,此时您将读取更多数据。

Note: each system call is expensive. 注意:每次系统调用都很昂贵。 It could take 2-5 micro-seconds. 它可能需要2-5微秒。 This doesn't sound like much unless you call it millions of times and it will add seconds to reading 1 MB. 这听起来不是很多,除非你打电话数百万次,它会增加读取1 MB的秒数。

Here´s the code of my final solution. 这是我最终解决方案的代码。

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;
    }
}

maybe this is a stupid question but wouldn't blocking IO solve this?也许这是一个愚蠢的问题,但不会阻止 IO 解决这个问题? (inputstream.readAllBytes()) you're blocking the thread anyway sincey ou hav to wait for the marker (inputstream.readAllBytes()) 无论如何你都在阻塞线程,因为你必须等待标记

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM