<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          淺析Java之BIO、NIO、AIO

          共 8725字,需瀏覽 18分鐘

           ·

          2022-04-01 20:49

          本文將介紹Java中幾種常見的網(wǎng)絡(luò)編程模型

          54e5bf6bfbc64ed6b5a4a1818ddd57a3.webp

          abstract.jpeg網(wǎng)絡(luò)IO模型

          對(duì)于一個(gè)網(wǎng)絡(luò)IO而言,其操作流程大體可分為兩個(gè)階段。這里以read操作為例進(jìn)行說明,write操作同理

          1. 數(shù)據(jù)準(zhǔn)備階段:等待數(shù)據(jù)從網(wǎng)絡(luò)中到達(dá),并將數(shù)據(jù)拷貝到內(nèi)核的Socket接收緩沖區(qū)
          2. 數(shù)據(jù)拷貝階段:將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間

          對(duì)于阻塞IO、非阻塞IO而言,其描述的是在第一個(gè)階段——數(shù)據(jù)準(zhǔn)備階段,發(fā)起IO請(qǐng)求的進(jìn)程/線程是否會(huì)被阻塞。具體地,對(duì)于阻塞IO而言,如果內(nèi)核接收緩沖區(qū)沒有數(shù)據(jù),則進(jìn)程/線程會(huì)一直等待,直到內(nèi)核接收緩沖區(qū)有數(shù)據(jù)為止;而對(duì)于非阻塞IO而言,如果內(nèi)核接收緩沖區(qū)沒有數(shù)據(jù),則進(jìn)程/線程會(huì)立即返回,而不是一直進(jìn)行等待。故對(duì)于非阻塞IO而言,可通過輪詢的方式檢查當(dāng)前是否有數(shù)據(jù)到達(dá)

          而對(duì)于同步、異步IO而言,其描述的是在第二個(gè)階段——數(shù)據(jù)拷貝階段,是否需要由用戶線程來執(zhí)行。具體地,同步IO是由用戶線程的內(nèi)核態(tài)來執(zhí)行第二階段;而異步IO則是由內(nèi)核自己完成第二個(gè)階段。在內(nèi)核完成數(shù)據(jù)拷貝后通知用戶線程,同時(shí)將數(shù)據(jù)以回調(diào)的形式傳遞給用戶線程。顯然對(duì)于同步IO而言,第二個(gè)階段的數(shù)據(jù)拷貝是由用戶線程參與完成的,故在第二個(gè)階段會(huì)發(fā)生阻塞;而對(duì)于異步IO而言,數(shù)據(jù)拷貝由于是內(nèi)核自己完成的,故在第二個(gè)階段不會(huì)發(fā)生阻塞

          網(wǎng)絡(luò)IO模型大致可分為兩類五種,其中同步IO有四種,異步IO有一種:

          1. 對(duì)于Bloking IO阻塞IO模型而言,其在Java中就是經(jīng)典的BIO。其特征為阻塞同步IO
          2. 對(duì)于Non-Blocking IO非阻塞IO模型而言,由于需要用戶線程不斷發(fā)起系統(tǒng)調(diào)用,頻繁地在內(nèi)核空間與用戶空間之間進(jìn)行切換,性能較低,故很少得到應(yīng)用
          3. 相比較Non-Blocking IO非阻塞IO模型,取而代之的是Multiplexing IO多路復(fù)用IO技術(shù)。其將前者頻繁地輪詢操作交由操作系統(tǒng)內(nèi)核來完成,是目前高并發(fā)網(wǎng)絡(luò)應(yīng)用的主流技術(shù)手段。其在Java中對(duì)應(yīng)的就是Java 1.4中引入的NIO,其特征為非阻塞同步IO
          4. 對(duì)于Signal-Driven IO信號(hào)驅(qū)動(dòng)IO模型而言,由于其不適用于TCP協(xié)議,故也很少被使用
          5. 對(duì)于Asynchronous IO異步IO模型來說,其在Java中對(duì)應(yīng)的就是Java 1.7中引入的AIO,其特征為非阻塞異步IO

          bdaa5a09a171a59c688d70724a56e746.webp

          figure 1.jpegBIO

          在Java 1.4之前BIO是Java網(wǎng)絡(luò)編程唯一的選擇,其特點(diǎn)是阻塞同步。由于accept、read方法均是阻塞操作。如果沒有連接請(qǐng)求,accept方法阻塞;如果無數(shù)據(jù)可讀取,read方法阻塞。故服務(wù)端側(cè)需要為每一個(gè)客戶端連接都提供一個(gè)線程。顯然在BIO模型下,如果存在大量客戶端連接,勢(shì)必增大服務(wù)端的壓力。甚至在極端情況下服務(wù)端會(huì)由于開啟的線程過多而最終宕機(jī),故為了保險(xiǎn)起見。最佳的實(shí)踐方式是通過線程池來提供、維護(hù)與客戶端通信所需的線程

          7565279d2b93b68a4062e572d22d8395.webp

          figure 2.jpeg

          這里給出BIO模型下的服務(wù)端編程示例

          /**
          ?*?BIO下的服務(wù)端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-15
          ?*/

          public?class?Server?{
          ????public?static?void?main(String[]?args)?{
          ????????try{
          ????????????ServerSocket?ss?=?new?ServerSocket(9999);
          ????????????while?(true)?{
          ????????????????//?阻塞等待客戶端連接
          ????????????????Socket?socket?=?ss.accept();
          ????????????????new?MsgHandler(?socket?).start();
          ????????????}
          ????????}catch?(IOException?e)?{
          ????????????System.out.println("[Server]:?Happen?Exception:?"+e.getMessage());
          ????????}
          ????}
          }

          class?MsgHandler?extends?Thread?{
          ????private?Socket?socket;

          ????public?MsgHandler(Socket?socket)?{
          ????????this.socket?=?socket;
          ????}

          ????@Override
          ????public?void?run()?{
          ????????try?{
          ????????????InputStream?inputStream?=?socket.getInputStream();
          ????????????BufferedReader?bufferedReader?=?new?BufferedReader(?new?InputStreamReader(inputStream));
          ????????????System.out.println("[Server]:?客戶端上線");
          ????????????String?msg;
          ????????????//?阻塞等待客戶端的輸入
          ????????????while?(?(msg=bufferedReader.readLine())?!=?null?)?{
          ????????????????if(?"Bye".equals(msg)?)?{
          ????????????????????break;
          ????????????????}
          ????????????????System.out.println("[Server]:?"?+?msg);
          ????????????}

          ????????????bufferedReader.close();
          ????????????socket.close();
          ????????}?catch?(Exception?e)?{
          ????????????System.out.println("[Server]:?Happen?Exception:?"+e.getMessage());
          ????????}

          ????????System.out.println("[Server]:?客戶端下線");
          ????}
          }

          這里給出BIO模型下的客戶端編程示例

          /**
          ?*?BIO下的客戶端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-15
          ?*/

          public?class?Client?{
          ????public?static?void?main(String[]?args)?{
          ????????try?(
          ????????????Socket?socket?=?new?Socket("127.0.0.1",?9999);
          ????????????PrintStream?printStream?=?new?PrintStream(socket.getOutputStream());
          ????????????Scanner?scanner?=?new?Scanner(System.in)?)?{

          ????????????while?(true)?{
          ????????????????System.out.print("[Client]:?請(qǐng)說:");
          ????????????????String?msg?=?scanner.nextLine();
          ????????????????if(?"Bye".equals(msg)?)?{
          ????????????????????break;
          ????????????????}

          ????????????????printStream.println(msg);
          ????????????????printStream.flush();
          ????????????}

          ????????????socket.shutdownOutput();
          ????????}?catch?(Exception?e)?{
          ????????????System.out.println("[Client]:?Happen?Exception:?"+e.getMessage());
          ????????}
          ????}
          }
          NIO

          Java從1.4開始引入了非阻塞同步的NIO。不同于BIO,其支持面向Buffer緩沖區(qū)的、基于Channel通道的IO操作。在NIO模型中,有三個(gè)核心部分:Buffer緩沖區(qū)、Channel通道、Selector選擇器

          「1. Buffer緩沖區(qū)」

          本質(zhì)上是一塊可以讀取、寫入數(shù)據(jù)的內(nèi)存空間,其被包裝為NIO Buffer對(duì)象。同時(shí)為了進(jìn)一步方便操作,還提供了一組相應(yīng)的API進(jìn)行操作、管理。為了方便理解,這里通過實(shí)踐的方式加強(qiáng)對(duì)緩沖區(qū)的認(rèn)識(shí)

          在Buffer中有兩個(gè)最重要的游標(biāo):position、limit。前者表示下一個(gè)將要被寫入或讀取的元素索引,當(dāng)調(diào)用get/put方法時(shí)會(huì)自動(dòng)更新。其中,初始化值為0;后者表示讀取、寫入元素時(shí)的界限。當(dāng)向Buffer寫完數(shù)據(jù)、準(zhǔn)備讀取時(shí),必須調(diào)用flip方法將其切換為可讀模式。具體地,其會(huì)將buffer的limit設(shè)置為pos的值、將pos設(shè)置0,以實(shí)現(xiàn)從頭讀取。與此同時(shí),可以通過clear方法將Buffer恢復(fù)至初始狀態(tài)。具體地,將pos的值歸零、limit設(shè)置為Buffer的容量值。這樣即可再次寫入數(shù)據(jù)以覆蓋歷史數(shù)據(jù)

          @Test
          public?void?test1()?{
          ????System.out.println("---------------Test?1?:?實(shí)例化---------------");
          ????ByteBuffer?buffer?=?ByteBuffer.allocate(15);
          ????System.out.println("capacity:?"?+?buffer.capacity());
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("---------------Test?2?:?寫數(shù)據(jù)---------------");
          ????String?msg?=?"BobAaronTina";
          ????buffer.put(?msg.getBytes()?);
          ????System.out.println("capacity:?"?+?buffer.capacity());
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("---------------Test?3?:?切換為可讀模式---------------");
          ????//?將buffer的limit設(shè)置為pos的值,?將pos設(shè)置0
          ????buffer.flip();
          ????System.out.println("capacity:?"?+?buffer.capacity());
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("---------------Test?4?:?讀取數(shù)據(jù)---------------");
          ????byte[]?bytes?=?new?byte[3];
          ????buffer.get(?bytes?);
          ????String?res?=?new?String(?bytes?);
          ????System.out.println("res?:?"+res);
          ????System.out.println("capacity:?"?+?buffer.capacity());
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("---------------Test?5?:?清空緩沖區(qū)---------------");
          ????//?將pos的值歸零、limit設(shè)置為Buffer的容量值
          ????buffer.clear();
          ????System.out.println("capacity:?"?+?buffer.capacity());
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());
          }

          測(cè)試結(jié)果,如下所示

          21b3e4de6021834a7042021b645a653d.webp

          figure 3.jpeg

          在Buffer中,可通過mark、reset方法分別實(shí)現(xiàn)將當(dāng)前pos值保存到mark變量中、將pos設(shè)置為mark變量的值。與此同時(shí),還可以通過hasRemaining、remaining方法分別實(shí)現(xiàn)判斷buffer中是否還有剩余元素、返回剩余元素的數(shù)量

          @Test
          public?void?test2()?{
          ????ByteBuffer?buffer?=?ByteBuffer.allocate(15);
          ????//?1.?寫數(shù)據(jù)
          ????String?msg?=?"USHelloChina";
          ????buffer.put(?msg.getBytes()?);
          ????//?2.?切換為讀模式
          ????buffer.flip();

          ????System.out.println("----------?第一次讀取?----------");
          ????for?(int?i=0;i<2;i++)?{
          ????????char?ch?=?(char)?buffer.get();
          ????????System.out.println("char?:?"?+?ch);
          ????}
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("----------?標(biāo)記位置?----------");
          ????//?將當(dāng)前pos值保存到mark變量中
          ????buffer.mark();

          ????System.out.println("----------?第二次讀取?----------");
          ????byte[]?bytes?=?new?byte[5];
          ????buffer.get(?bytes?);
          ????String?res?=?new?String(?bytes?);
          ????System.out.println("res?:?"+res);
          ????System.out.println("Buffer?Info:?"?+?buffer.toString());

          ????System.out.println("----------?回到標(biāo)記位置?----------");
          ????//?將pos設(shè)置為mark變量的值
          ????buffer.reset();
          ????System.out.println("position:?"?+?buffer.position());
          ????System.out.println("limit:?"?+?buffer.limit());

          ????System.out.println("----------?第三次讀取?----------");
          ????//?判斷buffer中是否還有剩余元素
          ????if?(?buffer.hasRemaining()?)?{
          ????????//?返回剩余元素的數(shù)量
          ????????int?size?=?buffer.remaining();
          ????????bytes?=?new?byte[size];
          ????????buffer.get(?bytes?);
          ????????res?=?new?String(?bytes?);
          ????????System.out.println("size?:?"+size);
          ????????System.out.println("res?:?"+res);
          ????????System.out.println("Buffer?Info:?"?+?buffer.toString());
          ????}

          }????

          測(cè)試結(jié)果,如下所示

          0f91ce8b4f6a9f8e651bcbf732ca301f.webp

          figure 4.jpeg

          事實(shí)上,Buffer實(shí)例所使用的內(nèi)存分為兩種:堆內(nèi)內(nèi)存(即非直接內(nèi)存)、堆外內(nèi)存(即直接內(nèi)存)

          @Test
          public?void?test3()?{
          ????//?創(chuàng)建堆內(nèi)內(nèi)存的Buffer實(shí)例,?實(shí)現(xiàn)類為?HeapByteBuffer
          ????Buffer?buffer1?=?ByteBuffer.allocate(15);
          ????//?該Buffer是否為直接內(nèi)存
          ????boolean?b1?=?buffer1.isDirect();
          ????System.out.println("是否為直接內(nèi)存:?"?+?b1);

          ????//?創(chuàng)建堆外內(nèi)存的Buffer實(shí)例,?實(shí)現(xiàn)類為DirectByteBuffer
          ????ByteBuffer?buffer2?=?ByteBuffer.allocateDirect(15);
          ????//?該Buffer是否為直接內(nèi)存
          ????boolean?b2?=?buffer2.isDirect();
          ????System.out.println("是否為直接內(nèi)存:?"?+?b2);
          }

          測(cè)試結(jié)果,如下所示

          3a603de7140c9952ee9b44f7326669d5.webp

          figure 5.jpeg

          「2. Channel通道」

          相比較傳統(tǒng)的單向流(輸入流、輸出流)而言,通道是雙向的。既可以讀數(shù)據(jù),也可以寫數(shù)據(jù)

          「3. Selector選擇器」

          Selector選擇器,也被稱作為多路復(fù)用器,是Java NIO中最重要的部分。其可以同時(shí)管理多個(gè)通道,并確定其中的哪些通道已經(jīng)準(zhǔn)備好進(jìn)行讀取、寫入操作。換言之,利用選擇器可以實(shí)現(xiàn)通過一個(gè)線程管理多個(gè)通道,即管理多個(gè)客戶端連接。NIO模型的示意圖如下所示

          b9c99a76cfbff0452b0d4d9cd8a7f3c1.webp

          figure 6.jpeg

          這里給出NIO模型下的服務(wù)端編程示例

          /**
          ?*?NIO下的服務(wù)端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-23
          ?*/

          public?class?Server?{
          ????public?static?void?main(String[]?args)?throws?IOException?{
          ????????//?獲取通道
          ????????ServerSocketChannel?serverSocketChannel?=?ServerSocketChannel.open();
          ????????//?切換為非阻塞模式
          ????????serverSocketChannel.configureBlocking(false);
          ????????//?綁定監(jiān)聽端口
          ????????serverSocketChannel.bind(?new?InetSocketAddress(8585)?);

          ????????//?獲取選擇器Selector
          ????????Selector?selector?=?Selector.open();
          ????????//?將通道注冊(cè)到選擇器中,?并開始監(jiān)聽客戶端連接類型的事件
          ????????serverSocketChannel.register(?selector,?SelectionKey.OP_ACCEPT);

          ????????//?使用Selector選擇器輪詢已經(jīng)就緒的事件
          ????????while?(?selector.select()>0?)?{
          ????????????//?獲取迭代器以進(jìn)行事件的遍歷、處理
          ????????????Iterator?it?=?selector.selectedKeys().iterator();

          ????????????while?(?it.hasNext()?)?{
          ????????????????//?通過迭代器獲取當(dāng)前事件
          ????????????????SelectionKey?selectionKey?=?it.next();

          ????????????????//?事件類型?為?接受連接事件
          ????????????????if(?selectionKey.isAcceptable()?)?{
          ????????????????????System.out.println("[Server]:?客戶端上線");
          ????????????????????//?獲取當(dāng)前連接進(jìn)來的客戶端通道
          ????????????????????SocketChannel?socketChannel?=?serverSocketChannel.accept();
          ????????????????????//?切換為非阻塞模式
          ????????????????????socketChannel.configureBlocking(false);
          ????????????????????//?將該客戶端通道注冊(cè)到選擇器中,?并開始監(jiān)聽讀就緒類型的事件
          ????????????????????socketChannel.register(selector,?SelectionKey.OP_READ);
          ????????????????}?else?if(?selectionKey.isReadable()?)?{????//?事件類型?為?讀就緒事件
          ????????????????????StringBuilder?sb?=?new?StringBuilder();
          ????????????????????//?通過事件獲取相應(yīng)的客戶端通道
          ????????????????????SocketChannel?socketChannel?=?(SocketChannel)?selectionKey.channel();
          ????????????????????//?創(chuàng)建一個(gè)Buffer實(shí)例,?用于存放從通道中讀取的數(shù)據(jù)
          ????????????????????ByteBuffer?buffer?=?ByteBuffer.allocate(5);
          ????????????????????int?len?=?0;
          ????????????????????//?從客戶端通道不停地讀取數(shù)據(jù)
          ????????????????????while?(?(len=socketChannel.read(buffer))?>?0?)?{
          ????????????????????????//?切換為讀模式
          ????????????????????????buffer.flip();
          ????????????????????????//?處理Buffer中的數(shù)據(jù)
          ????????????????????????String?temp?=?new?String(buffer.array(),?0,?len);
          ????????????????????????sb.append(?temp?);
          ????????????????????????//?清除Buffer
          ????????????????????????buffer.clear();
          ????????????????????}

          ????????????????????//?客戶端通道斷開連接
          ????????????????????if(?len==-1?)?{
          ????????????????????????//?取消注冊(cè)當(dāng)前事件的客戶端通道
          ????????????????????????selectionKey.cancel();
          ????????????????????????//?關(guān)閉客戶端通道
          ????????????????????????socketChannel.close();
          ????????????????????????System.out.println("[Server]:?客戶端下線");
          ????????????????????}

          ????????????????????System.out.println("[Server]:?"?+?sb.toString());
          ????????????????}

          ????????????????//?事件處理完畢后,移除當(dāng)前事件
          ????????????????it.remove();
          ????????????}
          ????????}
          ????}
          }

          這里給出NIO模型下的客戶端編程示例

          /**
          ?*?NIO下的客戶端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-24
          ?*/

          public?class?Client?{
          ????public?static?void?main(String[]?args)?throws?IOException?{
          ????????//?獲取客戶端通道
          ????????SocketChannel?socketChannel?=?SocketChannel.open(?new?InetSocketAddress("127.0.0.1",?8585));
          ????????//?切換為非阻塞模式
          ????????socketChannel.configureBlocking(false);
          ????????//?創(chuàng)建Buffer實(shí)例
          ????????int?bufferSize?=?5;
          ????????ByteBuffer?buffer?=?ByteBuffer.allocate(bufferSize);

          ????????Scanner?scanner?=?new?Scanner(System.in);
          ????????while?(true)?{
          ????????????System.out.print("[Client]:?請(qǐng)說:");
          ????????????String?msg?=?scanner.nextLine();
          ????????????if(?"Bye".equals(msg)?)?{
          ????????????????System.out.println("[Client]:?客戶端下線");
          ????????????????break;
          ????????????}

          ????????????byte[]?bytes?=?msg.getBytes();
          ????????????int?start?=?0;
          ????????????//?將客戶端的消息分批寫入Buffer、客戶端通道
          ????????????while?(?start?????????????????int?length?=?start?+?bufferSize?<=?bytes.length???bufferSize?:?bytes.length-start;
          ????????????????//?將客戶端消息部分寫入Buffer
          ????????????????buffer.put(bytes,?start,?length);
          ????????????????//?切換為讀模式
          ????????????????buffer.flip();
          ????????????????//?將客戶端消息部分寫入通道
          ????????????????socketChannel.write(?buffer?);
          ????????????????//?清除Buffer
          ????????????????buffer.clear();
          ????????????????//?更新下一次數(shù)據(jù)寫入的起點(diǎn)
          ????????????????start?=?start?+?length;
          ????????????}
          ????????}

          ????????//?關(guān)閉客戶端通道
          ????????socketChannel.close();
          ????}
          }
          AIO

          Java從1.7開始引入了非阻塞異步的AIO,作為對(duì)NIO的改進(jìn)、增強(qiáng),故其也被稱為NIO 2.0。其分別引入了服務(wù)端異步Socket通道AsynchronousServerSocketChannel、客戶端異步Socket通道AsynchronousSocketChannel,前者負(fù)責(zé)服務(wù)端Socket的創(chuàng)建、監(jiān)聽;后者負(fù)責(zé)客戶端消息的讀寫操作。同時(shí)提供了一個(gè)CompletionHandler,作為消息處理回調(diào)接口

          這里給出AIO模型下的服務(wù)端編程示例

          /**
          ?*?AIO下的服務(wù)端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-27
          ?*/

          public?class?Server?{
          ????public?static?void?main(String[]?args)?throws?IOException?{
          ????????//?獲取通道
          ????????AsynchronousServerSocketChannel?serverSocketChannel?=?AsynchronousServerSocketChannel.open();
          ????????//?綁定監(jiān)聽端口
          ????????serverSocketChannel.bind(?new?InetSocketAddress(9696)?);
          ????????//?準(zhǔn)備接受客戶端連接請(qǐng)求
          ????????serverSocketChannel.accept(?serverSocketChannel,?new?ServerHandler()?);

          ????????while?(true)?{
          ????????}
          ????}
          }

          當(dāng)接受到客戶端的連接請(qǐng)求后,我們需要提供一個(gè)相應(yīng)的CompletionHandler實(shí)現(xiàn)類。進(jìn)行業(yè)務(wù)邏輯處理。具體地,通過實(shí)現(xiàn)completed方法用于接受客戶端請(qǐng)求、建立連接后的業(yè)務(wù)處理邏輯,通過實(shí)現(xiàn)failed方法用于進(jìn)行服務(wù)端發(fā)生異常的處理邏輯。具體實(shí)現(xiàn)如下所示

          /**
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-27
          ?*/

          public?class?ServerHandler?implements?CompletionHandler<AsynchronousSocketChannel,?AsynchronousServerSocketChannel>?{
          ????/**
          ?????*?接受客戶端請(qǐng)求、建立連接后,?業(yè)務(wù)處理邏輯
          ?????*?@param?socketChannel?客戶端通道
          ?????*?@param?serverSocketChannel?服務(wù)端通道
          ?????*/

          ????@Override
          ????public?void?completed(AsynchronousSocketChannel?socketChannel,?AsynchronousServerSocketChannel?serverSocketChannel)?{
          ????????//?準(zhǔn)備接受下一個(gè)客戶端的連接請(qǐng)求
          ????????serverSocketChannel.accept(serverSocketChannel,?this);

          ????????//?創(chuàng)建Buffer實(shí)例
          ????????ByteBuffer?byteBuffer?=?ByteBuffer.allocate(2048);
          ????????socketChannel.read(?byteBuffer,?byteBuffer,?new?CompletionHandler()?{
          ????????????@Override
          ????????????public?void?completed(Integer?result,?ByteBuffer?attachment)?{
          ????????????????//?客戶端通道斷開連接
          ????????????????if(result?==?-1)?{
          ????????????????????try?{
          ????????????????????????//?關(guān)閉客戶端通道
          ????????????????????????socketChannel.close();
          ????????????????????}?catch?(IOException?e)?{
          ????????????????????????System.out.println("[Server]:?happen?exception,?"+e.getMessage());
          ????????????????????}
          ????????????????????return;
          ????????????????}

          ????????????????//?切換為讀模式
          ????????????????attachment.flip();
          ????????????????//?處理Buffer中的數(shù)據(jù)
          ????????????????String?msg?=?new?String(attachment.array(),?0,?result);
          ????????????????//?清除Buffer
          ????????????????attachment.clear();
          ????????????????System.out.println("[Server]:?"?+?msg);
          ????????????????//?準(zhǔn)備下一次讀
          ????????????????socketChannel.read(attachment,?attachment,?this);
          ????????????}

          ????????????@Override
          ????????????public?void?failed(Throwable?exc,?ByteBuffer?attachment)?{
          ????????????????System.out.println("[Server]:?happen?exception,?"+exc.getMessage());
          ????????????}
          ????????}?);
          ????}

          ????/**
          ?????*?服務(wù)端發(fā)生異常的處理邏輯
          ?????*?@param?exc
          ?????*?@param?serverSocketChannel
          ?????*/

          ????@Override
          ????public?void?failed(Throwable?exc,?AsynchronousServerSocketChannel?serverSocketChannel)?{
          ????????System.out.println("[Server]:?happen?exception,?"+exc.getMessage());
          ????}
          }

          這里給出AIO模型下的客戶端編程示例

          /**
          ?*?AIO下的客戶端
          ?*?@author?Aaron?Zhu
          ?*?@date?2022-03-27
          ?*/

          public?class?Client?{
          ????public?static?void?main(String[]?args)?throws?IOException?{
          ????????//?獲取通道
          ????????AsynchronousSocketChannel?socketChannel?=?AsynchronousSocketChannel.open();
          ????????//?請(qǐng)求連接服務(wù)端
          ????????socketChannel.connect(?new?InetSocketAddress("127.0.0.1",?9696));
          ????????//?創(chuàng)建Buffer實(shí)例
          ????????ByteBuffer?buffer?=?ByteBuffer.allocate(1024);

          ????????Scanner?scanner?=?new?Scanner(System.in);
          ????????while?(true)?{
          ????????????System.out.print("[Client]:?請(qǐng)說:");
          ????????????String?msg?=?scanner.nextLine();
          ????????????if(?"Bye".equals(msg)?)?{
          ????????????????System.out.println("[Client]:?客戶端下線");
          ????????????????break;
          ????????????}

          ????????????byte[]?bytes?=?msg.getBytes();
          ????????????//?將客戶端消息寫入Buffer
          ????????????buffer.put(?msg.getBytes()?);
          ????????????//?切換為讀模式
          ????????????buffer.flip();
          ????????????//?將客戶端消息部分寫入通道
          ????????????socketChannel.write(?buffer?);
          ????????????//?清除Buffer
          ????????????buffer.clear();
          ????????}

          ????????//?關(guān)閉客戶端通道
          ????????socketChannel.close();
          ????}
          }
          參考文獻(xiàn)
          1. 鳳凰架構(gòu) 周志明著
          瀏覽 28
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  三级久久久久久 | 大香蕉啪啪网 | 美女免费在线被干 | 成人午夜福利日韩高清亚洲 | A片免费观看在线 |