1 回答

TA貢獻1883條經驗 獲得超3個贊
如果您沒有調用configureBlocking(false)
,那么是的,您將使用循環來填充緩沖區。
然而……非阻塞套接字的要點是不要掛起等待任何一個套接字,因為這會延遲從所有剩余套接字(其選定的鍵尚未被迭代器處理)的讀取。實際上,如果十個客戶端連接,并且其中一個碰巧連接速度較慢,則其他部分或全部客戶端可能會遇到同樣的緩慢情況。
(未指定所選鍵集的確切順序。查看 Selector 實現類的源代碼是不明智的,因為缺乏任何順序保證意味著 Java SE 的未來版本可以更改順序。)
為了避免等待任何一個套接字,您不要嘗試一次性填滿緩沖區;相反,您可以在不阻塞的情況下讀取套接字可以提供的任何內容,每次調用只讀取一次select()
。
由于每個 ByteBuffer 可能保存部分數據序列,因此您需要記住每個 Socket 的每個 ByteBuffer 的進度。幸運的是,SelectionKey 有一個方便的方法來做到這一點:附件。
您還想記住從每個套接字讀取了多少字節。因此,現在您需要記住每個套接字的兩件事:字節數和字節緩沖區。
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)調用,但是正如您所看到的,使用阻塞通道可能會限制主服務器使用非阻塞通道的優勢。將與其他服務器的連接也設置為非阻塞通道可能是值得的。這會讓事情變得更加復雜,所以除非你希望我這樣做,否則我不會在這里解決這個問題。
添加回答
舉報