从 Java NIO socketchannel 读取字节直到到达标记
Read bytes from Java NIO socketchannel until marker is reached
我正在寻找一种使用 Java NIO 从套接字通道读取字节的有效方法。这个任务很简单,我有一个解决方案,尽管我正在寻找一种更清洁、更有效的方法来解决这个问题。场景如下:
- 从套接字通道读取数据
- 此数据是 UTF-8 编码的字符串
- 每行以\r\n结束,长度预先未知
- 读完每一行后,我想对消息做点什么
我的解决方案按字节读取数据字节,并将每个字节与我的标记(在 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);
}
尽管这样可以完成工作,但可能有更好的方法,不需要在每次迭代后进行每字节比较。
感谢您的帮助!
我的做法是尽可能多地读取可用的数据,例如 32 KB,一旦您读取了这个,就将数据逐字节复制到另一个缓冲区,例如一个字符串生成器。如果上次读取时缓冲区中还有数据,您可以继续使用该缓冲区,直到它全部消耗完,此时您可以读取更多数据。
注意:每次系统调用都是昂贵的。这可能需要 2-5 微秒。这听起来并不多,除非您调用它数百万次并且它会增加读取 1 MB 的秒数。
这是我最终解决方案的代码。
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;
}
}
我正在寻找一种使用 Java NIO 从套接字通道读取字节的有效方法。这个任务很简单,我有一个解决方案,尽管我正在寻找一种更清洁、更有效的方法来解决这个问题。场景如下:
- 从套接字通道读取数据
- 此数据是 UTF-8 编码的字符串
- 每行以\r\n结束,长度预先未知
- 读完每一行后,我想对消息做点什么
我的解决方案按字节读取数据字节,并将每个字节与我的标记(在 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);
}
尽管这样可以完成工作,但可能有更好的方法,不需要在每次迭代后进行每字节比较。
感谢您的帮助!
我的做法是尽可能多地读取可用的数据,例如 32 KB,一旦您读取了这个,就将数据逐字节复制到另一个缓冲区,例如一个字符串生成器。如果上次读取时缓冲区中还有数据,您可以继续使用该缓冲区,直到它全部消耗完,此时您可以读取更多数据。
注意:每次系统调用都是昂贵的。这可能需要 2-5 微秒。这听起来并不多,除非您调用它数百万次并且它会增加读取 1 MB 的秒数。
这是我最终解决方案的代码。
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;
}
}