亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

通過 SocketChannel 讀?。▽懭耄┑恼_方法

通過 SocketChannel 讀?。▽懭耄┑恼_方法

紅糖糍粑 2024-01-17 17:13:54
我的問題比以下場景更通用,盡管這涵蓋了所需的一切。這是針對Java和socket編程的正確做法。設想:一臺服務器有多個客戶端。非阻塞 I/O的使用該服務器是另一臺服務器的客戶端。阻塞 I/O的使用每種情況有兩種情況:在一種情況下,所有數據都適合分配的字節緩沖區,在第二種情況下,它們不適合(僅適用于一次迭代,不適用于程序的生命周期)。我發現的所有非阻塞 I/O 的示例都是這樣的:InetAddress host = InetAddress.getByName("localhost");Selector selector = Selector.open();ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.configureBlocking(false);serverSocketChannel.bind(new InetSocketAddress(host, 1234));serverSocketChannel.register(selector, SelectionKey. OP_ACCEPT);while (true) {   if (selector.select() <= 0)       continue;   Set<SelectionKey> selectedKeys = selector.selectedKeys();   Iterator<SelectionKey> iterator = selectedKeys.iterator();   while (iterator.hasNext()) {       key = (SelectionKey) iterator.next();       iterator.remove();       if (key.isAcceptable()) {           SocketChannel socketChannel = serverSocketChannel.accept();           socketChannel.configureBlocking(false);           socketChannel.register(selector, SelectionKey.OP_READ);           // Do something or do nothing       }       if (key.isReadable()) {           SocketChannel socketChannel = (SocketChannel) key.channel();           ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);           socketChannel.read(buffer);           // Something something dark side           if (result.length() <= 0) {               sc.close();               // Something else           }        }    }read如果緩沖區足夠大,這里是否讀取來自該特定客戶端和該特定請求的所有傳入數據,或者我是否需要將其放在循環內while?如果緩沖區不夠大?如果是 a write,我也可以這樣做嗎socketChannel.write(buffer)(至少從程序的角度來看)?這里的文檔沒有指定所有傳入數據都適合緩沖區的情況。當我有阻塞 I/O 時,這也會讓人有點困惑:然而,可以保證的是,如果通道處于阻塞模式并且緩沖區中至少剩余一個字節,則此方法將阻塞,直到至少讀取一個字節。這是否意味著這里(阻塞 I/O)我需要以任何一種方式read通過while循環(我發現的大多數示例都是這樣做的)?做手術怎么辦write?所以,總而言之,我的問題是,從中間服務器(客戶端到第二個服務器)的角度來看,在我的場景中讀寫數據的正確方法是什么?
查看完整描述

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)調用,但是正如您所看到的,使用阻塞通道可能會限制主服務器使用非阻塞通道的優勢。將與其他服務器的連接也設置為非阻塞通道可能是值得的。這會讓事情變得更加復雜,所以除非你希望我這樣做,否則我不會在這里解決這個問題。


查看完整回答
反對 回復 2024-01-17
  • 1 回答
  • 0 關注
  • 288 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號