国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java 網(wǎng)絡(luò)編程之NIO(selector)

這篇具有很好參考價(jià)值的文章主要介紹了Java 網(wǎng)絡(luò)編程之NIO(selector)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

? ? ? ? ? ? ? ?? ? ?本編文章意在循環(huán)漸進(jìn),可看最后一個(gè)就可以了

?

?Selector簡(jiǎn)介

Java 網(wǎng)絡(luò)編程之NIO(selector)

? 【1】創(chuàng)建Selector

? ? ? ? ? ? ?Selector selector = Selector.open();

? 【2】channel注冊(cè)到Selector

? ? ? ? ? ? ? ?首先channel必須是非阻塞的情況下

? ? ? ? ? ? ? ? channel.register(選擇器,操作的類型,綁定的組件);返回的是選擇鍵? ? ? ? ? ? ?

1)Channel 注冊(cè)到后,并且一旦通道處于某種就緒的狀態(tài),就可以被選擇器查詢到。
這個(gè)工作,使用選擇器 Selector 的 select()方法完成。select 方法的作用,對(duì)感興
趣的通道操作,進(jìn)行就緒狀態(tài)的查詢。
2)Selector 可以不斷的查詢 Channel 中發(fā)生的操作的就緒狀態(tài)。并且挑選感興趣
的操作就緒狀態(tài)。一旦通道有操作的就緒狀態(tài)達(dá)成,并且是 Selector 感興趣的操作,
就會(huì)被 Selector 選中,放入 選擇鍵集合 中。
3)一個(gè)選擇鍵,首先是包含了注冊(cè)在 Selector 的通道操作的類型,比方說(shuō)
SelectionKey.OP_READ。也包含了特定的通道與特定的選擇器之間的注冊(cè)關(guān)系。
開(kāi)發(fā)應(yīng)用程序是,選擇鍵是編程的關(guān)鍵。NIO 的編程,就是根據(jù)對(duì)應(yīng)的選擇鍵,進(jìn)行
不同的業(yè)務(wù)邏輯處理。
4)選擇鍵的概念,和事件的概念比較相似。一個(gè)選擇鍵類似監(jiān)聽(tīng)器模式里邊的一個(gè)
事件。由于 Selector 不是事件觸發(fā)的模式,而是主動(dòng)去查詢的模式,所以不叫事件
Event,而是叫 SelectionKey 選擇鍵。

【3】輪詢查詢就緒操作

1 )通過(guò) Selector select ()方法,可以查詢出已經(jīng)就緒的通道操作,這些就緒的
狀態(tài)集合,保存在一個(gè)元素是 SelectionKey 對(duì)象的 Set 集合中。
2 )下面是 Selector 幾個(gè)重載的查詢 select() 方法:
? ? ? ? ? ?- select(): 阻塞到至少有一個(gè)通道在你注冊(cè)的事件上就緒了。
? ? ? ? ? ?- select(long timeout) :和 select() 一樣,但最長(zhǎng)阻塞事件為 timeout 毫秒。
? ? ? ? ? ?- selectNow(): 非阻塞,只要有通道就緒就立刻返回。
select() 方法返回的 int 值,表示有多少通道已經(jīng)就緒,更準(zhǔn)確的說(shuō),是自前一次 select
方法以來(lái)到這一次 select 方法之間的時(shí)間段上,有多少通道變成就緒狀態(tài)。
例如:首次調(diào)用 select()方法,如果有一個(gè)通道變成就緒狀態(tài),返回了 1,若再次調(diào)用
select()方法,如果另一個(gè)通道就緒了,它會(huì)再次返回 1。如果對(duì)第一個(gè)就緒的
channel 沒(méi)有做任何操作,現(xiàn)在就有兩個(gè)就緒的通道,但在每次 select()方法調(diào)用之間,
只有一個(gè)通道就緒了。
Java 網(wǎng)絡(luò)編程之NIO(selector)
Java 網(wǎng)絡(luò)編程之NIO(selector)

?【4】停止選擇的方法

選擇器執(zhí)行選擇的過(guò)程, 系統(tǒng)底層會(huì)依次詢問(wèn)每個(gè)通道是否已經(jīng)就緒 ,這個(gè)過(guò)程可能會(huì)造成調(diào)用線程進(jìn)入阻塞狀態(tài),那么我們有以下方式可以喚醒在 select()方法中阻塞的線程。
? ? ? ? wakeup()方法 :通過(guò)調(diào)用 Selector 對(duì)象的 wakeup()方法讓處在阻塞狀態(tài)的 select()方法立刻返回該方法使得選擇器上的第一個(gè)還沒(méi)有返回的選擇操作立即返回。如果當(dāng)前沒(méi)有進(jìn)行中 的選擇操作,那么下一次對(duì) select()方法的一次調(diào)用將立即返回。
? ? ? ? close()方法 :通過(guò) close()方法關(guān)閉 Selector, 該方法使得任何一個(gè)在選擇操作中阻塞的線程都被喚醒(類似 wakeup()),同時(shí) 使得注冊(cè)到該 Selector 的所有 Channel 被注銷,所有的鍵將被取消, 但是 Channel 本身并不會(huì)關(guān)閉

NIO 編程步驟

第一步:創(chuàng)建 Selector 選擇器
第二步:創(chuàng)建 ServerSocketChannel 通道,并綁定監(jiān)聽(tīng)端口
第三步:設(shè)置 Channel 通道是非阻塞模式
第四步:把 Channel 注冊(cè)到 Socketor 選擇器上,監(jiān)聽(tīng)連接事件
第五步:調(diào)用 Selector 的 select 方法(循環(huán)調(diào)用),監(jiān)測(cè)通道的就緒狀況
第六步:調(diào)用 selectKeys 方法獲取就緒 channel 集合
第七步:遍歷就緒 channel 集合,判斷就緒事件類型,實(shí)現(xiàn)具體的業(yè)務(wù)操作
第八步:根據(jù)業(yè)務(wù),決定是否需要再次注冊(cè)監(jiān)聽(tīng)事件,重復(fù)執(zhí)行第三步操作

代碼1.0

public class SelectorServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel  ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.configureBlocking(false);
        //創(chuàng)建selector選擇器
        Selector selector = Selector.open();
        //將ssc注冊(cè)到選器器(建立兩者的聯(lián)系)
        SelectionKey sscKey = ssc.register(selector, 0, null);
        //選擇哪種監(jiān)聽(tīng)的事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();//阻塞方法,如果沒(méi)有事件發(fā)生,線程將在此處停止
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();//返回所有可能發(fā)生事件的key集合(set)
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                System.out.println("key::"+key);
                ServerSocketChannel channel = (ServerSocketChannel) key.channel();//獲取相對(duì)應(yīng)的channel
                SocketChannel sc = channel.accept();
                sc.configureBlocking(false);
                SelectionKey scKey = sc.register(selector, 0, null);
                System.out.println("scKey---->"+scKey);
                scKey.interestOps(SelectionKey.OP_READ);
                System.out.println("sc已經(jīng)在selector中注冊(cè)了!");
            }
        }
    }
}

?結(jié)果分析:

Java 網(wǎng)絡(luò)編程之NIO(selector)

? ? ?

Java 網(wǎng)絡(luò)編程之NIO(selector)

?解決方案

【1】區(qū)分觸發(fā)seletor.select()的事件

【2】處理完一個(gè)事件,在對(duì)應(yīng)的注冊(cè)的keys集合刪除。

?代碼2.0

public class SelectorServer {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel  ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.configureBlocking(false);
        Selector selector = Selector.open();
        SelectionKey sscKey = ssc.register(selector, 0, null);
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();//阻塞方法,如果沒(méi)有事件發(fā)生,線程將在此處停止
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();//返回所有可能發(fā)生事件的key集合(set)
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                iterator.remove();//解決處理后事件在set集合中還有的現(xiàn)象
                if (key.isAcceptable()){//區(qū)分不同事件觸發(fā)的結(jié)果
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();//獲取相對(duì)應(yīng)的channel
                    SocketChannel sc = channel.accept();
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, 0, null);
                    System.out.println("scKey---->"+scKey);
                    scKey.interestOps(SelectionKey.OP_READ);
                    System.out.println("sc已經(jīng)在selector中注冊(cè)了!");
                }else if (key.isReadable()){
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(32);
                    int len = channel.read(buffer);
                    buffer.flip();
                    System.out.println(StandardCharsets.UTF_8.decode(buffer).toString());
                    buffer.clear();
                }


            }
        }
    }
}

Java 網(wǎng)絡(luò)編程之NIO(selector)

?新的問(wèn)題 如果ByteBuffer分配的空間不夠用會(huì)出現(xiàn)什么結(jié)果(分析)

? ? ? ?當(dāng)一次沒(méi)有讀完后就會(huì)觸發(fā)下一次的讀取,

Java 網(wǎng)絡(luò)編程之NIO(selector)

?解決方案:為每一個(gè)連接客戶端的channel的ByteBuffer的空間動(dòng)態(tài)擴(kuò)容,(可以避免黏包半包的情況?。?/p>

Java 網(wǎng)絡(luò)編程之NIO(selector)

?新的問(wèn)題:

當(dāng)客戶端強(qiáng)制關(guān)機(jī),服務(wù)器停止

Java 網(wǎng)絡(luò)編程之NIO(selector)

?當(dāng)客戶端正常結(jié)束,服務(wù)器進(jìn)入無(wú)限循環(huán)

Java 網(wǎng)絡(luò)編程之NIO(selector)

解決方案:

客戶端強(qiáng)制關(guān)機(jī),服務(wù)器報(bào)異常,使用try--catch語(yǔ)句? key.cancel()對(duì)此不做任何事情

客戶端正常結(jié)束,客戶端向服務(wù)器發(fā)送數(shù)據(jù),read = -1;

代碼3.0(最終篇)

public class SelectorServer {
    
    public static void main(String[] args) throws Exception {
        ServerSocketChannel  ssc = ServerSocketChannel.open();
        ssc.bind(new InetSocketAddress(8080));
        ssc.configureBlocking(false);
        Selector selector = Selector.open();
        SelectionKey sscKey = ssc.register(selector, 0, null);
        sscKey.interestOps(SelectionKey.OP_ACCEPT);

        while (true){
            selector.select();//阻塞方法,如果沒(méi)有事件發(fā)生,線程將在此處停止
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();//返回所有可能發(fā)生事件的key集合(set)
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                iterator.remove();//解決處理后事件在set集合中還有的現(xiàn)象
                if (key.isAcceptable()){//區(qū)分不同事件觸發(fā)的結(jié)果
                    ServerSocketChannel channel = (ServerSocketChannel) key.channel();//獲取相對(duì)應(yīng)的channel
                    SocketChannel sc = channel.accept();
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, 0, null);
                    System.out.println("scKey---->"+scKey);
                    ByteBuffer buffer = ByteBuffer.allocate(4);
                    scKey.attach(buffer);//為每一個(gè)注冊(cè)到set集合中的channel分配獨(dú)立的緩沖區(qū)
                    scKey.interestOps(SelectionKey.OP_READ);
                    System.out.println("sc已經(jīng)在selector中注冊(cè)了!");
                }else if (key.isReadable()){
                    try {
                        SocketChannel channel = (SocketChannel) key.channel();
                        ByteBuffer buffer = (ByteBuffer) key.attachment();
                        int read = channel.read(buffer);
//                    System.out.println("read::"+read);
//                    System.out.println("positon:"+buffer.position()+"limit:"+buffer.limit());
                        System.out.println(buffer);
                        if (read == -1){//客戶端正常結(jié)束,read的值等于-1
                            key.cancel();
                            continue;
                        }
                        if(read == buffer.capacity()){
                            ByteBuffer newBuffer = ByteBuffer.allocate(buffer.capacity()*2);
                            newBuffer.flip();
                            newBuffer.put(buffer);
                            key.attach(newBuffer);
                        }else{
                            buffer.flip();
                            System.out.println(StandardCharsets.UTF_8.decode(buffer).toString());
                            buffer.clear();
                        }
                    } catch (IOException e) {
                        e.printStackTrace();
                        key.cancel();
                    }

                }


            }
        }
    }
}

結(jié)果:

客戶端正常結(jié)束

Java 網(wǎng)絡(luò)編程之NIO(selector)

?客戶端強(qiáng)制結(jié)束Java 網(wǎng)絡(luò)編程之NIO(selector)

?

?Selector寫事件與讀事件類似

服務(wù)器

public class SelectorWriter {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress(8080));

        Selector selector = Selector.open();
        ssc.register(selector, SelectionKey.OP_ACCEPT, null);

        while (true){
            selector.select();
            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()){
                SelectionKey key = iterator.next();
                iterator.remove();
                if (key.isAcceptable()){
                    SocketChannel sc = ssc.accept();
                    sc.configureBlocking(false);
                    SelectionKey sckey = sc.register(selector, SelectionKey.OP_READ);

                    //發(fā)送大量的數(shù)據(jù)
                    StringBuilder str = new StringBuilder();
                    for (int i = 0; i < 300000; i++) {
                        str.append("a");
                    }
                    ByteBuffer buffer = Charset.defaultCharset().encode(str.toString());
                    int write = sc.write(buffer);
                    System.out.println(write);
                    if (buffer.hasRemaining()){
                        // 4. 關(guān)注可寫事件
                        sckey.interestOps(sckey.interestOps() + SelectionKey.OP_WRITE);
                       // sckey.interestOps(sckey.interestOps() | SelectionKey.OP_WRITE);
                        // 5. 把未寫完的數(shù)據(jù)掛到 sckey 上
                        sckey.attach(buffer);
                    }

                }else if(key.isWritable()){
                    SocketChannel sc = (SocketChannel) key.channel();
                    ByteBuffer buffer = (ByteBuffer) key.attachment();
                    int write = sc.write(buffer);
                    System.out.println(write);
                    //清理工作
                    if (!buffer.hasRemaining()){
                        key.attach(null);
                        key.interestOps(key.interestOps() - SelectionKey.OP_WRITE);
                    }
                
                }
            }
        }
    }
}

?客戶端

public class WriterClient {
    public static void main(String[] args) throws Exception {
        SocketChannel sc = SocketChannel.open();
        sc.connect(new InetSocketAddress("localhost", 8080));

        // 3. 接收數(shù)據(jù)
        int count = 0;
        while (true) {
            ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);
            count += sc.read(buffer);
            System.out.println(count);
            buffer.clear();
        }
    }
}

Java 網(wǎng)絡(luò)編程之NIO(selector)文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-410041.html

到了這里,關(guān)于Java 網(wǎng)絡(luò)編程之NIO(selector)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • BIO、NIO、IO多路復(fù)用模型詳細(xì)介紹&Java NIO 網(wǎng)絡(luò)編程

    BIO、NIO、IO多路復(fù)用模型詳細(xì)介紹&Java NIO 網(wǎng)絡(luò)編程

    上文介紹了網(wǎng)絡(luò)編程的基礎(chǔ)知識(shí),并基于 Java 編寫了 BIO 的網(wǎng)絡(luò)編程。我們知道 BIO 模型是存在巨大問(wèn)題的,比如 C10K 問(wèn)題,其本質(zhì)就是因其阻塞原因,導(dǎo)致如果想要承受更多的請(qǐng)求就必須有足夠多的線程,但是足夠多的線程會(huì)帶來(lái)內(nèi)存占用問(wèn)題、CPU上下文切換帶來(lái)的性能問(wèn)題

    2024年02月14日
    瀏覽(30)
  • Java網(wǎng)絡(luò)編程----通過(guò)實(shí)現(xiàn)簡(jiǎn)易聊天工具來(lái)聊聊NIO

    Java網(wǎng)絡(luò)編程----通過(guò)實(shí)現(xiàn)簡(jiǎn)易聊天工具來(lái)聊聊NIO

    前文我們說(shuō)過(guò)了BIO,今天我們聊聊NIO。 NIO 是什么?NIO官方解釋它為 New lO ,由于其特性我們也稱之為,Non-Blocking IO。這是jdk1.4之后新增的一套IO標(biāo)準(zhǔn)。 為什么要用NIO呢? 我們?cè)俸?jiǎn)單回顧下BIO: 阻塞式IO,原理很簡(jiǎn)單,其實(shí)就是多個(gè)端點(diǎn)與服務(wù)端進(jìn)行通信時(shí),每個(gè)客戶端有一個(gè)

    2024年02月05日
    瀏覽(20)
  • Java網(wǎng)絡(luò)編程(二)NIO和Netty實(shí)現(xiàn)多人聊天功能
  • NIO基礎(chǔ) - 網(wǎng)絡(luò)編程

    NIO基礎(chǔ) - 網(wǎng)絡(luò)編程

    non-blocking io 非阻塞 IO 1.1 Channel Buffer channel 有一點(diǎn)類似于 stream,它就是讀寫數(shù)據(jù)的 雙向通道 ,可以從 channel 將數(shù)據(jù)讀入 buffer,也可以將 buffer 的數(shù)據(jù)寫入 channel,而之前的 stream 要么是輸入,要么是輸出,channel 比 stream 更為底層 常見(jiàn)的 Channel 有 FileChannel DatagramChannel SocketCh

    2024年02月02日
    瀏覽(19)
  • 10.NIO 網(wǎng)絡(luò)編程應(yīng)用實(shí)例-群聊系統(tǒng)

    需求:進(jìn)一步理解 NIO 非阻塞網(wǎng)絡(luò)編程機(jī)制,實(shí)現(xiàn)多人群聊 編寫一個(gè) NIO 群聊系統(tǒng),實(shí)現(xiàn)客戶端與客戶端的通信需求(非阻塞) 服務(wù)器端:可以監(jiān)測(cè)用戶上線,離線,并實(shí)現(xiàn)消息轉(zhuǎn)發(fā)功能 客戶端:通過(guò) channel 可以無(wú)阻塞發(fā)送消息給其它所有客戶端用戶,同時(shí)可以接受其它客戶端用

    2024年02月15日
    瀏覽(44)
  • 由淺入深Netty基礎(chǔ)知識(shí)NIO網(wǎng)絡(luò)編程

    由淺入深Netty基礎(chǔ)知識(shí)NIO網(wǎng)絡(luò)編程

    阻塞模式下,相關(guān)方法都會(huì)導(dǎo)致線程暫停 ServerSocketChannel.accept 會(huì)在沒(méi)有連接建立時(shí)讓線程暫停 SocketChannel.read 會(huì)在沒(méi)有數(shù)據(jù)可讀時(shí)讓線程暫停 阻塞的表現(xiàn)其實(shí)就是線程暫停了,暫停期間不會(huì)占用 cpu,但線程相當(dāng)于閑置 單線程下,阻塞方法之間相互影響,幾乎不能正常工作,

    2024年02月05日
    瀏覽(28)
  • 【Netty專題】【網(wǎng)絡(luò)編程】從OSI、TCP/IP網(wǎng)絡(luò)模型開(kāi)始到BIO、NIO(Netty前置知識(shí))

    【Netty專題】【網(wǎng)絡(luò)編程】從OSI、TCP/IP網(wǎng)絡(luò)模型開(kāi)始到BIO、NIO(Netty前置知識(shí))

    我是有點(diǎn)怕網(wǎng)絡(luò)編程的,總有點(diǎn)【談網(wǎng)色變】的感覺(jué)。為了讓自己不再【談網(wǎng)色變】,所以我想過(guò)系統(tǒng)學(xué)習(xí)一下,然后再做個(gè)筆記這樣,加深一下理解。但是真要系統(tǒng)學(xué)習(xí),其實(shí)還是要花費(fèi)不少時(shí)間的,所以這里也只是簡(jiǎn)單的,盡可能地覆蓋一下,梳理一些我認(rèn)為比較迫切需

    2024年02月06日
    瀏覽(28)
  • Java NIO Selector選擇器源碼分析

    Java NIO Selector選擇器源碼分析

    Java NIO(New I/O)的Selector選擇器是一個(gè)用于多路復(fù)用(Multiplexing)的I/O操作的關(guān)鍵組件。它允許一個(gè)單獨(dú)的線程監(jiān)視多個(gè)通道(Channel)的可讀性和可寫性,從而有效地管理大量并發(fā)連接。 AbstractSelector主要實(shí)現(xiàn)了Selector的打開(kāi)關(guān)閉的狀態(tài)維護(hù),支持異步關(guān)閉和中斷的begin和end方

    2024年04月10日
    瀏覽(17)
  • Java-NIO篇章(4)——Selector選擇器詳解

    Java-NIO篇章(4)——Selector選擇器詳解

    選擇器(Selector)是什么呢?選擇器和通道的關(guān)系又是什么?這里詳細(xì)說(shuō)明,假設(shè)不用選擇器,那么一個(gè)客戶端請(qǐng)求數(shù)據(jù)傳輸那就需要建立一個(gè)連接,為了避免線程阻塞,那么每個(gè)客戶端開(kāi)辟一個(gè)線程。而學(xué)過(guò)JVM的都知道,默認(rèn)每開(kāi)一個(gè)線程需要??臻g內(nèi)存1MB大小。如果這時(shí)

    2024年01月21日
    瀏覽(31)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包