亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么在Java中使用NIO的Write事件

發布時間:2021-06-01 16:13:09 來源:億速云 閱讀:229 作者:Leah 欄目:開發技術

這期內容當中小編將會給大家帶來有關怎么在Java中使用NIO的Write事件,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

一、NIO Server端

1.1 多路復用開發一般步驟

//打開選擇器
Selector selector = Selector.open();
//打開通到
ServerSocketChannel socketChannel = ServerSocketChannel.open();
//配置非阻塞模型
socketChannel.configureBlocking(false);
//綁定端口
socketChannel.bind(new InetSocketAddress(8080));
//注冊事件,OP_ACCEPT只適用于ServerSocketChannel 
socketChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
    selector.select();
    Set<SelectionKey> selectionKeys = selector.selectedKeys();
    Iterator<SelectionKey> iter = selectionKeys.iterator();
    while(iter.hasNext()) {
        SelectionKey key = iter.next();
        if(key.isAcceptable()) {
            SocketChannel channel = ((ServerSocketChannel)key.channel()).accept();
            channel.configureBlocking(false);
            channel.register(selector,SelectionKey.OP_READ);
        }
        
        if(key.isWritable()) {
        }
        
        if(key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer readBuffer = ByteBuffer.allocate(1024);
            channel.read(readBuffer);
            readBuffer.flip();
            // handler Buffer
            // 一般是響應客戶端的數據
            // 直接是write寫不就完事了嘛,為啥需要write事件?
            // channel.write(...)
        }
        iter.remove();
    }
}

1.2 解惑寫事件

對NIO的寫操作:

  • 為什么要注冊寫事件

  • 何時注冊寫事件

  • 為什么寫完之后要取消注冊寫事件

如果有channel在Selector上注冊了SelectionKey.OP_WRITE,在調用selector.select();時,系統會檢查內核寫緩沖區是否可寫:

  • 如果可寫,selector.select();立即返回,進入key.isWritable()

  • 何時不可寫?比如緩沖區已滿,channel調用了shutdownOutPut等

當然除了注冊寫事件,你也可以在channel直接調用write(…),也可以將數據發出去,但這樣不夠靈活,而且可能浪費CPU。

比如服務端需要發送一個200M的Buffer,看看是否使用OP_WRITE事件的區別。

二、不使用事件

程序運行到這會等到200M文件發送完成后才繼續往下執行,不符合異步事件模型的思想。若緩沖區一直處不可寫狀態,則該過程一直在這里死循環,浪費CPU。

// 200M的Buffer
ByteBuffer buffer = .... 

while(buffer.hasRemaining()) {
    // 該方法只會寫入小于socket's output buffer空閑區域的任何字節數
    // 并返回寫入的字節數,可能是0字節
    channel.write(buffer);
}

三、使用事件

if(key.isReadable()) {
	// 200M Buffer
    ByteBuffer buffer = .... 
    // 注冊寫事件
    key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
    // 綁定Buffer
    key.attach(buffer);
}
// 可寫分支
if(key.isWritable()) {
    ByteBuffer buffer = (ByteBuffer) key.attachment();
    SocketChannel channel = (SocketChannel) key.channel();
    if (buffer.hasRemaining()) {
        channel.write(buffer)
    } else {
        // 發送完了就取消寫事件,否則下次還會進入寫事件分支(因為只要還可寫,就會進入)
        key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE);
    }
}

要觸發寫事件,需要先向 selector 注冊該通道的寫事件,跟注冊讀事件一樣,當底層寫緩沖區有空閑就會觸發寫事件了,而一般來說底層的寫緩沖區大部分都是空閑的。所以一般只要注冊了寫事件,就會立馬觸發了,為了避免 cpu 空轉,在寫操作完成后需要把寫事件取消掉,然后下次再有寫操作時重新注冊寫事件。

四、NIO Client端

開發的一般步驟

// 打開選擇器
Selector selector = Selector.open();
// 打開通道
SocketChannel socketChannel = SocketChannel.open();
// 配置非阻塞模型
socketChannel.configureBlocking(false);
// 連接Server
socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));
// 注冊事件
socketChannel.register(selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);
// 循環處理
while (true) {
    selector.select();
    Set<SelectionKey> keys = selector.selectedKeys();
    Iterator<SelectionKey> iter = keys.iterator();
    while(iter.hasNext()) {
        SelectionKey key = iter.next();
        if(key.isConnectable()) {
            // 連接建立或者連接建立不成功
            SocketChannel channel = (SocketChannel) key.channel();
            // 完成連接建立
            if(channel.finishConnect()) {
                
            }
        }
        
        if(key.isReadable()) {
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(500 * 1024 * 1024);
            buffer.clear();
            channel.read(buffer);
            // buffer Handler
        }
        iter.remove();
    }
}

起初對OP_CONNECT事件還有finishConnect不理解,OP_CONNECT事件何時觸發,特別是為什么要在key.isConnectable()分支里調用finishConnect方法后才能進行讀寫操作。

首先,在non-blocking模式下調用socketChannel.connect(new InetSocketAddress(“127.0.0.1”,8080));連接遠程主機,如果連接能立即建立就像本地連接一樣,該方法會立即返回true,否則該方法會立即返回false,然后系統底層進行三次握手建立連接。連接有兩種結果,一種是成功連接,第二種是異常,但是connect方法已經返回,無法通過該方法的返回值或者是異常來通知用戶程序建立連接的情況,所以由OP_CONNECT事件和finishConnect方法來通知用戶程序。不管系統底層三次連接是否成功,selector都會被喚醒繼而觸發OP_CONNECT事件,如果握手成功,并且該連接未被其他線程關閉,finishConnect會返回true,然后就可以順利的進行channle讀寫。如果網絡故障,或者遠程主機故障,握手不成功,用戶程序可以通過finishConnect方法獲得底層的異常通知,進而處理異常。

上述就是小編為大家分享的怎么在Java中使用NIO的Write事件了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節
推薦閱讀:
  1. Java NIO
  2. java中的NIO介紹

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

虞城县| 含山县| 黄平县| 平谷区| 阿拉善右旗| 河间市| 仪陇县| 南开区| 大田县| 区。| 汪清县| 河南省| 沙田区| 板桥市| 北票市| 明溪县| 新密市| 汝南县| 西平县| 诸城市| 荣昌县| 南召县| 双牌县| 铜陵市| 青田县| 乌什县| 贵港市| 扶余县| 东乡族自治县| 鹤岗市| 清镇市| 临澧县| 嫩江县| 留坝县| 洪泽县| 吴堡县| 榆树市| 石门县| 万宁市| 彭阳县| 江北区|