Read bytes from Java NIO socketchannel until token is reached

I am looking for an efficient way to read bytes from a socket pipe using Java NIO. The task is quite simple, I have a solution, although I am looking for a cleaner and more efficient way to solve this problem. Here's the script:

  • Data is read from the socket pipe
  • This data is a UTF-8 encoded string
  • Each line ends with \ r \ n, the length is unknown in front
  • After every line read I want to do something with the message

My solution reads byte of data per byte and compares each byte against my marker (which has a value of 10 in UTF-8 codepages). Here is 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);
}

      

While it does the job, there might be a better way that doesn't need these byte comparisons after each iteration.

Thank you for your help!

+3


source to share


2 answers


The way I am going to do this is to read as much as is available, for example 32KB, and once you read this, you will copy the data byte byte to another buffer, for example. StringBuilder. If the last time you read the data left in the buffer, you can continue to use the buffer until it is used, at which point you will read more data.



Note: every system call is expensive. This may take 2-5 microseconds. It doesn't seem like a lot unless you call it millions of times and it adds seconds to read 1MB.

+3


source


Here is the code for 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;
    }
}

      

0


source







All Articles