1 回答

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