SocketChannel.read() блокирует неблокирующий канал

Иногда я сталкивался со случаем, когда SocketChannel.read() блокирует неблокирующий канал (варианты JDK 1.6 на RH6). Мое чтение спецификации говорит, что это никогда не должно происходить. После добавления большого тайм-аута в сокет (который, я думаю, никогда не понадобится...), я вижу следующее: java.io.IOException: Connection timed out at sun.nio.ch.FileDispatcherImpl.read0(Native method) ... at sun.nio.ch.SocketChannelImpl.read(SocketChannelImpl.java:380) ... Глядя на источник, это просто вызов read(), который, по-видимому, не должен блокироваться в файле. дескриптор с установленным O_NONBLOCK.

(Это может быть похоже на: SocketChannel.read() блокирует на неопределенный срок, однако в моем случае канал определенно был настроен как неблокирующий, и синхронизация действительно не должна иметь здесь значения, ИМХО, поскольку вызов не должен блокироваться независимо от любых других соображений.)

Я знаю, что неблокирующий read() может заблокироваться из-за, скажем, пейджинга, но время ожидания моего сокета установлено на несколько минут, поэтому пейджинг не может быть виновником.

Любые идеи?

Код установки:

public void addConnection(SocketChannel channel) throws SocketException {
    channel.socket().setTcpNoDelay(true);
    channel.socket().setReceiveBufferSize(defReceiveBufferSize);
    channel.socket().setSendBufferSize(defSendBufferSize);
    channel.socket().setSoTimeout(defSocketReadTimeout);
    try {
        channel.configureBlocking(false);
    } catch (IOException ioe) {
        Log.logErrorWarning(ioe);
        throw new RuntimeException("Unable to configure non-blocking socket");
   ...
}

person user8870183    schedule 01.11.2017    source источник
comment
Можете ли вы опубликовать код настройки и использования SocketChannel?   -  person phflack    schedule 01.11.2017
comment
К сожалению, полный код слишком сложен для публикации. Я добавил соответствующий код установки. Использование просто numRead = socketChannelInstance.read(buffer).   -  person user8870183    schedule 01.11.2017


Ответы (1)


«Время ожидания подключения истекло» означает сетевую ошибку, а не тайм-аут чтения.

Здесь нет никаких доказательств того, что чтение действительно заблокировано. Сетевая ошибка уже находилась там, ожидая операции ввода-вывода, чтобы сообщить о ней. Ваш read() немедленно вернулся, вызвав это исключение.

Нет смысла устанавливать тайм-аут чтения на неблокирующем канале сокета.

person user207421    schedule 02.11.2017
comment
Хороший улов. Я смотрел на тайм-аут и предположил, что это произошло из-за тайм-аута read(), но, вероятно, это разорванное соединение. Тестовый код показывает, что socketChannelInstance.read(buffer) все равно игнорирует тайм-аут сокета. У меня есть некоторые доказательства задержек в операциях. Я еще немного поинструментирую, чтобы получить достоверные данные о времени. Хороший лид. - person user8870183; 02.11.2017