Если бы вы не вызвали configureBlocking(false)
, тогда да, вы бы использовали цикл для заполнения буфера.
Однако ... смысл неблокирующего сокета не в том, чтобы зависнуть в ожидании какого-либоодин сокет, так как это приведет к задержке чтения из всех остальных сокетов, чьи выбранные ключи еще не были обработаны вашим итератором. Фактически, если десять клиентов соединяются, и у одного из них медленное соединение, некоторые или все другие могут испытывать ту же медлительность.
(Точный порядок выбранного набора ключей не указан. было бы неразумно смотреть на источник класса реализации Selector, поскольку отсутствие какой-либо гарантии порядка означает, что будущие версии Java SE могут изменять порядок.)
Чтобы избежать ожидания какого-либо одного сокета,Вы не пытаетесь заполнить буфер все за один раз;скорее, вы читаете все, что сокет может дать вам без блокировки, читая только один раз за select()
вызов.
Поскольку каждый ByteBuffer может содержать частичную последовательность данных, вам нужно будет помнить прогресс каждого ByteBuffer для каждогоРазъем. К счастью, у SelectionKey есть удобный способ сделать это: вложение .
Вы также хотите запомнить, сколько байтов вы прочитали из каждого сокета. Итак, теперь у вас есть две вещи, которые вы должны запомнить для каждого сокета: счетчик байтов и ByteBuffer.
class ReadState {
final ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
long count;
}
while (true) {
// ...
if (key.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
// Attach the read state for this socket
// to its corresponding key.
socketChannel.register(selector, SelectionKey.OP_READ,
new ReadState());
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
ReadState state = (ReadState) key.attachment();
ByteBuffer buffer = state.buffer;
state.count += socketChannel.read(buffer);
if (state.count >= DATA_LENGTH) {
socketChannel.close();
}
buffer.flip();
// Caution: The speed of this connection will limit your ability
// to process the remaining selected keys!
anotherServerChannel.write(buffer);
}
Для канала блокировки вы можете просто использовать один вызов write(buffer)
, но, как выМожно видеть, что использование канала блокировки может ограничить преимущества использования неблокирующими каналами основного сервера. Возможно, стоит сделать подключение к другому серверу неблокирующим каналом. Это усложнит ситуацию, поэтому я не буду говорить об этом здесь, если вы не хотите, чтобы я это сделал.