здесь важный код:Как улучшить производительность следующего кода с помощью socketchannel? И как я могу получить строку UTF8?
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. Но я не знаю, как использовать указанную кодировку в этом случае.
Edit: я решил свою "бесконечный цикл" проблема, вот фиксированный код:
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();
}
}
я непреднамеренно создал sligthly дублировать нить. Мои навыки 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();
}
не связана с реальной проблемой, но вы можете начать с фиксацией * непроверенные * предупреждения, что ваш код генерирует (например, 'selectedKeys() 'возвращает общий набор). Это также снимает необходимость приведения. – dhke
Вам действительно нужно использовать NIO? Вы можете взглянуть на Netty (http://netty.io/), что делает его намного проще. –
Мне не нужно использовать NIO. Я просто новичок в Java, и я не знал о netty. Я запомню это в следующий раз. благодаря – Jan