В настоящее время я использую неблокирующий SocketChannel (Java 1.6) в качестве клиента для сервера Redis. Redis принимает текстовые команды непосредственно через сокет, завершается CRLF и отвечает аналогичным образом, быстрый пример:
ОТПРАВИТЬ: 'PING\r\n'
RECV: '+PONG\r\n'
Redis также может возвращать огромные ответы (в зависимости от того, что вы запрашиваете) со многими разделами \r\n-терминированных данных как часть одного ответа.
Я использую стандартный цикл while(socket.read() › 0) {//append bytes} для чтения байтов из сокета и повторной сборки их на стороне клиента в ответ.
ПРИМЕЧАНИЕ. Я не использую селектор, а использую несколько каналов SocketChannel на стороне клиента, подключенных к серверу и ожидающих обработки команд отправки/получения.
Что меня смущает, так это контракт метода SocketChannel.read() в неблокирующем режиме, в частности, как узнать, когда сервер закончил отправку, и я есть все сообщение.
У меня есть несколько способов защиты от слишком быстрого возврата и предоставления серверу возможности ответить, но единственное, на чем я застрял, это:
- Возможно ли когда-нибудь, чтобы read() возвращал байты, а затем при последующем вызове не возвращал байтов, но при другом последующем вызове снова возвращал несколько байтов?
В принципе, могу ли я доверять тому, что сервер ответил мне, если я получил хотя бы 1 байт и в конечном итоге read() возвращает 0, тогда я знаю, что закончил, или, возможно, сервер был просто занят и может выдать еще несколько байтов, если я подожду и продолжу попытки?
Если он может продолжать отправлять байты даже после того, как read() вернул 0 байтов (после предыдущих успешных операций чтения), то я понятия не имею, как определить, когда сервер закончил говорить со мной, и на самом деле я сбит с толку, как связь в стиле java.io. * даже узнает, когда сервер готов.
Как вы, ребята, знаете, чтение никогда не возвращает -1, если только соединение не разорвано, а это стандартные долгоживущие соединения с БД, поэтому я не буду закрывать и открывать их при каждом запросе.
Я знаю, что популярный ответ (по крайней мере, на эти вопросы NIO) заключался в том, чтобы взглянуть на Grizzly, MINA или Netty - если возможно, я действительно хотел бы узнать, как все это работает в исходном состоянии, прежде чем принимать некоторые сторонние зависимости.
Спасибо.
Дополнительный вопрос:
Первоначально я думал, что блокирующий SocketChannel будет подходящим способом, поскольку я действительно не хочу, чтобы вызывающий абонент что-либо делал, пока я не обработаю его команду и не верну ему ответ.
Если это окажется лучшим способом, я был немного сбит с толку, увидев, что SocketChannel.read() блокирует до тех пор, пока не будет байтов, достаточных для заполнения данного буфера... за исключением чтения всего побайтно Я не могу понять, как это поведение по умолчанию на самом деле предназначено для использования... Я никогда не знаю точный размер ответа, возвращаемого с сервера, поэтому мои вызовы SocketChannel.read() всегда блокировать до истечения времени ожидания (в этот момент я наконец вижу, что содержимое находится в буфере).
Я не совсем понимаю, как правильно использовать метод блокировки, поскольку он всегда зависает при чтении.