Есть сервер (однопоточный nio) работающий с клиентами, все работает корректно кроме того, что после первого ответа клиенту метод select перестает блокировать поток (в котором был вызван), но все продолжает работать, а процессор загружен на максимум (причем при дебаге все работает).
Создается ServerSocketChannel так:
Selector selector = SelectorProvider.provider().openSelector();
ServerSocketChannel serverChanel = ServerSocketChannel.open();
serverChanel.configureBlocking(false);
serverChanel.register(selector, serverChanel.validOps());
serverChanel.bind(new InetSocketAddress(lisenHost, listenPort));
while(true) {
selector.select(); //С какого-то момента не блокирует и как правило возвращает 0
Iterator<SelectionKey> selectionKeys = selector.selectedKeys().iterator();
logger.debug(selectionKeys.hasNext());
...
Присоединение клиента происходит так
SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
socketChannel.configureBlocking(false);
socketChannel.register(key.selector(), SelectionKey.OP_READ);
Если сам сервер куда-то конектится это происходит так:
SocketChannel hostSocket = SocketChannel.open();
hostSocket.configureBlocking(false);
hostSocket.register(key.selector(), SelectionKey.OP_CONNECT);
hostSocket.connect(new InetSocketAddress(address, port));
...
if (key.isConnectable()) {
((SocketChannel) key.channel()).finishConnect();
key.interestOps(SelectionKey.OP_READ);
}
Когда надо что-то записать слушаю SelectionKey.OP_READ | SelectionKey.OP_WRITE
.
После записи выполняю key.interestOps(SelectionKey.OP_READ)
И после выполнения операции на запись select() перестает блокировать (если заменить key.interestOps(SelectionKey.OP_READ)
на key.interestOps(0)
, то select() остается блокирующим).
В чем может быть проблема?
select()
возвращает 0 в том случае, когда зарегистрированные в селекторе сокеты перешли в состояние готовности ещё до вызова select()
.
Скорее всего проблема связана с тем, что сокеты всегда готовы к записи, если ваш сервер не генерирует поток данных полностью исчерпывающий пропускную способность сетевого интерфейса. Поэтому регистрировать сокет с OP_WRITE
стоит только тогда, когда вам есть, что в него писать, а после вызывать key.cancel()
.
И небольшая рекомендация: Поменяйте порядок следования вызовов bind
и register
. Регистрировать в селекторе стоит только уже открытые соединения.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Как найти одинаковые слова в предложении и вывести эти предложения? Есть идея вначале, получить предложения:
Нужно вывести список самых популярных компаний по языкам программированияНе понимаю как отделить компании по языкам