如何使用 socketchannel 提高以下代码的性能?我怎样才能收到 UTF8 字符串?
How to improve the performance of the following code using socketchannel? And how can I receive UTF8 string?
这里是重要的代码:
public void setSelector() {
try {
this.writebuf.clear();
this.selector = Selector.open();
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
SelectionKey selectionKey = this.socketChannel.register(selector, interestSet);
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
int bytesRead = 0;
while (selector.select() > -1) {
// Wait for an event one of the registered channels
// Iterate over the set of keys for which events are available
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
if (bytesRead > 0 && writebuf.hasRemaining()) {
this.writebuf.flip();
this.parseSubtitleMessage(new String(writebuf.array(), charset));
this.writebuf.clear();
this.writebuf.flip();
}
}
if (key.isWritable()) {
// Not yet implemented
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Socketchannel
设置为 nonblocking
模式。
第一个问题是 while 循环会产生巨大的工作量。基本上,我需要一些可以 pause
代码直到 READ
或 WRITE
event
发生的东西。
另一个有问题的部分是这段代码:
this.parseSubtitleMessage(new String(writebuf.array(), charset));
我知道,当我调用 array()
方法时,我将获得整个缓冲区,其中包括前一条消息中的一些 forgotten
字节,即使我调用了 clear
方法。我找到了一个解决方案,它使用 while 循环迭代单个字节,直到 buffer.hasRemaining()
设置为 false。但是我不知道在这种情况下如何使用指定的字符集。
编辑:
我解决了我的 "infinite loop" 问题,这里是固定代码:
public void runSelector() {
try {
this.writebuf.clear();
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
this.selector = Selector.open();
int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
int bytesRead = 0;
SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (!key.isValid()) {
continue;
}
// Check if there's something to write in the queue and change interestops apropriately.
if (monitorObject.tosendIsEmpty()) {
selectionKey.interestOps(SelectionKey.OP_READ);
} else {
selectionKey.interestOps(interestSet_RW);
}
if (key.isWritable()) {
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
if (bytesRead > 0 && writebuf.hasRemaining()) {
this.parseSubtitleMessage(new String(this.writebuf.array(), charset));
this.writebuf.clear();
}
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
我无意中创建了稍微重复的线程。那天我的 google 技能可能真的很糟糕。
但是第二个问题仍然存在,我非常感谢您的帮助。谢谢
编辑 2:所以我也解决了第二个问题。这是代码:
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
bytes = new byte[bytesRead];
int x = 0;
this.writebuf.flip();
while(this.writebuf.hasRemaining()) {
bytes[x] = this.writebuf.get();
x++;
}
System.out.println(new String(bytes, charset));
this.writebuf.flip();
this.writebuf.clear();
}
这是最终的解决方案:
public void runSelector() {
try {
this.writebuf.clear();
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
this.selector = Selector.open();
int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
int bytesRead = 0;
byte[] bytes = null;
SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (!key.isValid()) {
continue;
}
// Check if there's something to write in the queue and change interestops apropriately.
if (monitorObject.tosendIsEmpty()) {
selectionKey.interestOps(SelectionKey.OP_READ);
} else {
selectionKey.interestOps(interestSet_RW);
}
if (key.isWritable()) {
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
bytes = new byte[bytesRead];
int x = 0;
this.writebuf.flip();
while(this.writebuf.hasRemaining()) {
bytes[x] = this.writebuf.get();
x++;
}
System.out.println(new String(bytes, charset));
this.writebuf.flip();
this.writebuf.clear();
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
这里是重要的代码:
public void setSelector() {
try {
this.writebuf.clear();
this.selector = Selector.open();
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
SelectionKey selectionKey = this.socketChannel.register(selector, interestSet);
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
int bytesRead = 0;
while (selector.select() > -1) {
// Wait for an event one of the registered channels
// Iterate over the set of keys for which events are available
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
if (bytesRead > 0 && writebuf.hasRemaining()) {
this.writebuf.flip();
this.parseSubtitleMessage(new String(writebuf.array(), charset));
this.writebuf.clear();
this.writebuf.flip();
}
}
if (key.isWritable()) {
// Not yet implemented
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Socketchannel
设置为 nonblocking
模式。
第一个问题是 while 循环会产生巨大的工作量。基本上,我需要一些可以 pause
代码直到 READ
或 WRITE
event
发生的东西。
另一个有问题的部分是这段代码:
this.parseSubtitleMessage(new String(writebuf.array(), charset));
我知道,当我调用 array()
方法时,我将获得整个缓冲区,其中包括前一条消息中的一些 forgotten
字节,即使我调用了 clear
方法。我找到了一个解决方案,它使用 while 循环迭代单个字节,直到 buffer.hasRemaining()
设置为 false。但是我不知道在这种情况下如何使用指定的字符集。
编辑: 我解决了我的 "infinite loop" 问题,这里是固定代码:
public void runSelector() {
try {
this.writebuf.clear();
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
this.selector = Selector.open();
int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
int bytesRead = 0;
SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (!key.isValid()) {
continue;
}
// Check if there's something to write in the queue and change interestops apropriately.
if (monitorObject.tosendIsEmpty()) {
selectionKey.interestOps(SelectionKey.OP_READ);
} else {
selectionKey.interestOps(interestSet_RW);
}
if (key.isWritable()) {
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
if (bytesRead > 0 && writebuf.hasRemaining()) {
this.parseSubtitleMessage(new String(this.writebuf.array(), charset));
this.writebuf.clear();
}
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
我无意中创建了稍微重复的线程。那天我的 google 技能可能真的很糟糕。 但是第二个问题仍然存在,我非常感谢您的帮助。谢谢
编辑 2:所以我也解决了第二个问题。这是代码:
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
bytes = new byte[bytesRead];
int x = 0;
this.writebuf.flip();
while(this.writebuf.hasRemaining()) {
bytes[x] = this.writebuf.get();
x++;
}
System.out.println(new String(bytes, charset));
this.writebuf.flip();
this.writebuf.clear();
}
这是最终的解决方案:
public void runSelector() {
try {
this.writebuf.clear();
// Checking if the buffer is in write mode
if (!(this.writebuf.limit() == this.writebuf.capacity())) {
writebuf.flip();
}
this.selector = Selector.open();
int interestSet_RW = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
int bytesRead = 0;
byte[] bytes = null;
SelectionKey selectionKey = this.socketChannel.register(selector, SelectionKey.OP_READ);
while(true) {
int readyChannels = selector.select();
if(readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (!key.isValid()) {
continue;
}
// Check if there's something to write in the queue and change interestops apropriately.
if (monitorObject.tosendIsEmpty()) {
selectionKey.interestOps(SelectionKey.OP_READ);
} else {
selectionKey.interestOps(interestSet_RW);
}
if (key.isWritable()) {
}
if (key.isReadable()) {
bytesRead = this.socketChannel.read(this.writebuf);
bytes = new byte[bytesRead];
int x = 0;
this.writebuf.flip();
while(this.writebuf.hasRemaining()) {
bytes[x] = this.writebuf.get();
x++;
}
System.out.println(new String(bytes, charset));
this.writebuf.flip();
this.writebuf.clear();
}
keyIterator.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}