国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

異步非阻塞網(wǎng)絡(luò)通訊技術(shù)研究

2019-12-03 04:14:56段楠
現(xiàn)代計(jì)算機(jī) 2019年17期
關(guān)鍵詞:網(wǎng)絡(luò)通訊監(jiān)聽(tīng)內(nèi)核

段楠

(吉林大學(xué)軟件學(xué)院,長(zhǎng)春130000)

1 網(wǎng)絡(luò)通訊的方式

在網(wǎng)絡(luò)通訊的開(kāi)發(fā)中,存在著同步/異步、阻塞/非阻塞的多種方式,不同方式的軟件性能與開(kāi)發(fā)成本各不相同,可根據(jù)軟件需求進(jìn)行選擇。以下介紹同步/異步、阻塞/非阻塞在網(wǎng)絡(luò)通訊中的概念,和應(yīng)用程序與操作系統(tǒng)內(nèi)核之間同步/異步、阻塞/非阻塞的概念不盡相同。

1.1 同步與異步

同步與異步在網(wǎng)絡(luò)通訊環(huán)境下更傾向于對(duì)客戶端通訊方式的描述。

同步是指客戶端向服務(wù)器發(fā)送請(qǐng)求后,必須等到服務(wù)器的響應(yīng)到來(lái)才可進(jìn)行下一步操作。

異步是指客戶端向服務(wù)器發(fā)送請(qǐng)求后,不必等待服務(wù)器響應(yīng)并可繼續(xù)其他操作,待服務(wù)器發(fā)來(lái)響應(yīng)后,客戶端會(huì)得到I/O 操作完成的通知,只需對(duì)結(jié)果進(jìn)行處理即可。

1.2 阻塞與非阻塞

阻塞與非阻塞在網(wǎng)絡(luò)通訊環(huán)境下更傾向于對(duì)服務(wù)器通訊方式的描述。

阻塞是指服務(wù)器在接受某個(gè)客戶端的請(qǐng)求后,觸發(fā)相應(yīng)函數(shù),無(wú)論能不能執(zhí)行都會(huì)一直等待,直到當(dāng)前函數(shù)執(zhí)行結(jié)束后才能進(jìn)行下一步操作。

非阻塞是指服務(wù)器在接收客戶端的請(qǐng)求后,向操作系統(tǒng)注冊(cè)I/O 監(jiān)聽(tīng),如果當(dāng)前不能讀寫(xiě)會(huì)立刻返回并執(zhí)行其他操作。當(dāng)讀寫(xiě)可執(zhí)行時(shí),操作系統(tǒng)會(huì)通知服務(wù)器應(yīng)用程序執(zhí)行讀寫(xiě)操作,觸發(fā)相應(yīng)函數(shù)。

1.3 Java的三種網(wǎng)絡(luò)通訊方式

Java 在網(wǎng)絡(luò)通訊方面最早只有實(shí)現(xiàn)同步阻塞方式的BIO 組件,BIO 服務(wù)器的實(shí)現(xiàn)方式為給每一個(gè)客戶端的連接提供一個(gè)進(jìn)程。即使當(dāng)前客戶端沒(méi)有執(zhí)行任何操作,該線程也會(huì)一直阻塞等待。這種方式顯然會(huì)帶來(lái)很大的資源浪費(fèi)。在這種方式下實(shí)現(xiàn)并發(fā)連接需要對(duì)服務(wù)器使用多線程技術(shù),為每個(gè)客戶端連接增加一個(gè)新的線程??梢?jiàn),這種方式會(huì)消耗大量的資源。

在JDK 1.4 之后,Java 開(kāi)始支持同步非阻塞的通訊方式,即NIO 組件。NIO 服務(wù)器的實(shí)現(xiàn)方式為給每個(gè)客戶端的請(qǐng)求提供一個(gè)線程??蛻舳说倪B接會(huì)注冊(cè)到多路復(fù)用器上,多路復(fù)用器進(jìn)行輪詢,當(dāng)某個(gè)連接有I/O請(qǐng)求時(shí)啟動(dòng)一個(gè)線程進(jìn)行處理。

在JDK 7 之后,Java 推出了具有異步非阻塞通訊功能的AIO 組件。AIO 服務(wù)器的實(shí)現(xiàn)方式為給每個(gè)有效請(qǐng)求提供一個(gè)進(jìn)程。即操作系統(tǒng)對(duì)I/O 請(qǐng)求執(zhí)行完之后,再通知服務(wù)器應(yīng)用程序啟動(dòng)線程進(jìn)行處理。

以上三種通訊方式可根據(jù)軟件應(yīng)用的具體需求進(jìn)行選擇。BIO 適合并發(fā)量較小的應(yīng)用,且對(duì)服務(wù)器的資源要求較高。但實(shí)現(xiàn)方式簡(jiǎn)單,可快速開(kāi)發(fā)。NIO適合并發(fā)量較大且多數(shù)為短連接的應(yīng)用,實(shí)現(xiàn)方式較為復(fù)雜。AIO 適合并發(fā)量較大且多數(shù)為長(zhǎng)連接的應(yīng)用,會(huì)調(diào)動(dòng)操作系統(tǒng)實(shí)現(xiàn)并發(fā)操作,實(shí)現(xiàn)方式較為復(fù)雜。

2 異步非阻塞通訊

2.1 異步非阻塞

同步/異步、阻塞/非阻塞原本是應(yīng)用程序與操作系統(tǒng)交互時(shí)的一組概念。同步與異步指的是應(yīng)用程序的方法調(diào)用是否需要等待結(jié)果的返回,才能進(jìn)行其他操作。阻塞與非阻塞指的是一個(gè)讀寫(xiě)操作是否需要等待操作系統(tǒng)內(nèi)核的所有讀寫(xiě)完成,才算完成。而在網(wǎng)絡(luò)通訊中這組概念使用的也是系統(tǒng)內(nèi)核中的基本原理,因此了解系統(tǒng)內(nèi)核中異步非阻塞的原理是十分有必要的。

在應(yīng)用程序與系統(tǒng)內(nèi)核交互中,異步指的是,應(yīng)用程序調(diào)用讀寫(xiě)操作方法后,不須一直等待結(jié)果的返回,而是可以繼續(xù)進(jìn)行其他的操作。當(dāng)讀寫(xiě)完成后,會(huì)由操作系統(tǒng)通知到應(yīng)用程序,再由應(yīng)用程序?qū)Y(jié)果進(jìn)行處理。

非阻塞是指在系統(tǒng)底層,進(jìn)行一個(gè)讀寫(xiě)操作時(shí)CPU 無(wú)須等待當(dāng)前操作的所有內(nèi)核I/O 全部完成,而是每個(gè)內(nèi)核I/O 完成之后會(huì)立刻返回一個(gè)狀態(tài),此時(shí)CPU 就可以繼續(xù)執(zhí)行其他任務(wù)。當(dāng)某個(gè)讀寫(xiě)操作的內(nèi)核I/O 全部完成之后,該讀寫(xiě)操作完成。而CPU 需要判斷某個(gè)讀寫(xiě)操作當(dāng)前是否有內(nèi)核I/O 請(qǐng)求,以及確認(rèn)讀寫(xiě)操作是否完成并取得數(shù)據(jù),這就需要CPU 對(duì)讀寫(xiě)操作的控制機(jī)制。主要有“輪詢”和“中斷”兩種機(jī)制?!拜喸儭笔侵窩PU 通過(guò)循環(huán)對(duì)所有I/O 訪問(wèn),得知當(dāng)前讀寫(xiě)操作的狀態(tài)。輪詢過(guò)程中應(yīng)用程序需要等待CPU的詢問(wèn),因此是一種同步非阻塞的方式?!爸袛唷笔侵缸x寫(xiě)操作有I/O 請(qǐng)求時(shí)主動(dòng)請(qǐng)求CPU 為其分配內(nèi)核資源。而應(yīng)用程序在發(fā)送讀寫(xiě)請(qǐng)求后只需等待系統(tǒng)將結(jié)果返回即可,此時(shí)可執(zhí)行其他操作,因此時(shí)一種異步非阻塞的方式。

系統(tǒng)內(nèi)核層面的異步非阻塞,與網(wǎng)絡(luò)通訊層面的異步非阻塞原理大致相同,只是描述對(duì)象有所差別。上述“輪詢”方式類似于Java NIO 的實(shí)現(xiàn)方式,服務(wù)器對(duì)客戶端的請(qǐng)求進(jìn)行輪詢處理,來(lái)查找某個(gè)客戶端是

否有數(shù)據(jù)請(qǐng)求。上述“中斷”方式類似于Java AIO 的實(shí)現(xiàn)方式,客戶端的請(qǐng)求到來(lái)后,首先由操作系統(tǒng)進(jìn)行I/O操作,然后將結(jié)果通知給服務(wù)器應(yīng)用程序,進(jìn)行一些處理后再返回響應(yīng)給客戶端。此時(shí)客戶端不需要等待服務(wù)器的輪詢,只需等待結(jié)果即可。Java AIO 顯然是一種異步非阻塞的通訊方式,以下詳細(xì)闡述該技術(shù)。

2.2 Java異步非阻塞通訊原理

Java 異步非阻塞通訊組件AIO 使用“訂閱-通知”方式進(jìn)行實(shí)現(xiàn)。即服務(wù)器應(yīng)用程序向操作系統(tǒng)注冊(cè)I/O監(jiān)聽(tīng),當(dāng)操作系統(tǒng)完成I/O 操作之后,通知服務(wù)器應(yīng)用程序進(jìn)行處理,觸發(fā)相應(yīng)函數(shù)。

在服務(wù)器應(yīng)用程序中,當(dāng)需要讀寫(xiě)時(shí)只需調(diào)用read 和write 方法。這兩種方法都是非阻塞的。進(jìn)行read 操作時(shí),操作系統(tǒng)將客戶端的I/O 請(qǐng)求處理完成后,將數(shù)據(jù)放入read 的緩沖區(qū),并通知服務(wù)器應(yīng)用程序?qū)?shù)據(jù)進(jìn)行處理。進(jìn)行write 操作時(shí),服務(wù)器應(yīng)用程序?qū)?shù)據(jù)寫(xiě)入write 緩沖區(qū),操作系統(tǒng)從緩沖區(qū)取得數(shù)據(jù)并進(jìn)行I/O 操作,操作完成后通知服務(wù)器應(yīng)用程序進(jìn)行回調(diào)操作。read 和write 可在讀寫(xiě)操作完成后通過(guò)回調(diào)函數(shù)的方式進(jìn)行回調(diào)操作。回調(diào)方法包括completed方法和failed 方法。completed 方法在讀寫(xiě)操作成功后回調(diào)執(zhí)行,一般會(huì)在其中對(duì)ByteBuffer 數(shù)據(jù)進(jìn)行業(yè)務(wù)邏輯處理,以及遞歸調(diào)用下一個(gè)讀寫(xiě)操作。failed 方法在讀寫(xiě)操作失敗后回調(diào)執(zhí)行,一般向控制臺(tái)或日志文件打印異常信息。

AIO 中有如下幾個(gè)重要元素:

Channel:是應(yīng)用程序與操作系統(tǒng)之間的通道,通過(guò)該通道可實(shí)現(xiàn)應(yīng)用程序與操作系統(tǒng)之間的數(shù)據(jù)傳輸。Channel 包括:AsynchronousServerSocketChannel,實(shí)現(xiàn)服務(wù)器應(yīng)用程序?qū)Σ僮飨到y(tǒng)的監(jiān)聽(tīng)與操作系統(tǒng)對(duì)服務(wù)器應(yīng)用程序的通知。AsynchronousSocketChannel,實(shí)現(xiàn)服務(wù)器對(duì)TCP 套接字的監(jiān)聽(tīng)。DatagramChannel,實(shí)現(xiàn)服務(wù)器對(duì)UDP 套接字的監(jiān)聽(tīng)。AsynchronousFileChannel,實(shí)現(xiàn)服務(wù)器應(yīng)用程序?qū)ξ募?shù)據(jù)I/O 的監(jiān)聽(tīng)。

ByteBuffer:為每一種Channel 提供的數(shù)據(jù)緩存區(qū),用于Channel 中數(shù)據(jù)的交換。ByteBuffer 中有一個(gè)指向當(dāng)前讀寫(xiě)位置的索引,每次讀寫(xiě)結(jié)束后會(huì)停留在最后數(shù)據(jù)的位置。因此每個(gè)ByteBuffer 對(duì)應(yīng)的通道在每次讀操作前,需要使用flip 方法將該索引回到初始位置。每次讀操作后,需要使用clear 方法將ByteBuffer清空,以便下次讀入。

Attachment:通道的附件,在嵌套或遞歸的讀寫(xiě)操作中起到上下文的作用。

3 Java異步非阻塞通訊實(shí)現(xiàn)

以時(shí)間發(fā)送程序?yàn)槔?,給出Java AIO 實(shí)現(xiàn)的一個(gè)簡(jiǎn)單示范。服務(wù)器每收到一個(gè)客戶端請(qǐng)求,就發(fā)送系統(tǒng)當(dāng)前時(shí)間響應(yīng)給客戶端。

3.1 服務(wù)器關(guān)鍵代碼

首先創(chuàng)建AsynchronousServerSocketChannel,可以用線程池的方式創(chuàng)建。

ExecutorService executor=Executors.newFixedThreadPool(20);

AsynchronousChannelGroup group=AsynchronousChannel-Group.withThreadPool(executor);

AsynchronousServerSocketChannel serverSocketChannel=AsynchronousServerSocketChannel.open(group);

然后對(duì)指定的主機(jī)及端口進(jìn)行綁定,并監(jiān)聽(tīng)發(fā)來(lái)的連接請(qǐng)求。監(jiān)聽(tīng)方法中一定要綁定回調(diào)方法來(lái)執(zhí)行監(jiān)聽(tīng)成功后的下一步操作。需要自己編寫(xiě)Completion-Handler 接口的實(shí)現(xiàn)類,并重寫(xiě)completed 與failed方法。

serverSocketChannel.bind (new InetSocketAddress ("0.0.0.0",33335));

serverSocketChannel.accept(null,new AcceptHandler(serverSocketChannel));

以下為CompletionHandler 接口的實(shí)現(xiàn)類AcceptHandler 的completed 方法,參數(shù)需要Asynchronous-SocketChannel 作為當(dāng)前連接客戶端的通道,attachment可根據(jù)需要決定是否傳入有效數(shù)據(jù)。

public void completed(AsynchronousSocketChannel socketChannel,Object attachment)

遞歸進(jìn)行客戶端連接監(jiān)聽(tīng)。

serverSocketChannel.accept(attachment,this);

讀取客戶端發(fā)來(lái)的數(shù)據(jù)。將需要發(fā)送的數(shù)據(jù)用ByteBuffer 封裝并傳入第一個(gè)參數(shù)。第二個(gè)參數(shù)為attachment,如不需要上下文對(duì)象可傳入null。第三個(gè)參數(shù)即回調(diào)方法類,可使用匿名內(nèi)部類的方式實(shí)現(xiàn)。

ByteBuffer buffer=ByteBuffer.allocate(1024);

socketChannel.read(buffer,null,new CompletionHandler(){

讀取客戶端發(fā)來(lái)的消息并解碼。

buffer.flip();

String request=StandardCharsets.UTF_8.decode(buffer).toString();

處理業(yè)務(wù)邏輯。write 方法向客戶端寫(xiě)入響應(yīng)數(shù)據(jù),由于不需要遞歸調(diào)用所以只傳入數(shù)據(jù)緩沖參數(shù)即可。

if(request.equals("time")){

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

String date=sdf.format(new Date());

socketChannel.write(ByteBuffer.wrap(date.getBytes("utf-8"))).get();

}else{

socketChannel.write(ByteBuffer.wrap("非法輸入".get-Bytes("utf-8"))).get();

}

遞歸進(jìn)行下次數(shù)據(jù)讀取。

buffer.clear();

socketChannel.read(buffer,null,this);

3.2 客戶端關(guān)鍵代碼

客戶端首先要打開(kāi)AsynchronousSocketChannel 并連接服務(wù)器。

AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open();

socketChannel.connect (new InetSocketAddress ("127.0.0.1",33335)).get();

執(zhí)行寫(xiě)操作,給服務(wù)器發(fā)送請(qǐng)求。

socketChannel.write (ByteBuffer.wrap (request.getBytes("utf-8")),null,newCompletionHandler()

讀取服務(wù)器發(fā)來(lái)的響應(yīng)。

ByteBuffer buffer=ByteBuffer.allocate(1024);

socketChannel.read(buffer,null,new CompletionHandler()

進(jìn)行輸出,之后清空緩沖區(qū)。

buffer.flip();

String response=StandardCharsets.UTF_8.decode(buffer).toString();

System.out.println(response);

buffer.clear();

遞歸調(diào)用下次寫(xiě)操作,實(shí)現(xiàn)客戶端可重復(fù)向服務(wù)器發(fā)送數(shù)據(jù)。

String request=in.readLine();

socketChannel.write (ByteBuffer.wrap (request.getBytes("utf-8")),null,this);

4 結(jié)語(yǔ)

本文首先介紹了同步與異步、阻塞與非阻塞的概念,從操作系統(tǒng)內(nèi)核的原始原理到網(wǎng)絡(luò)通訊的具體情形對(duì)異步非阻塞進(jìn)行了具體闡述。然后以Java 開(kāi)發(fā)為例,給出了異步非阻塞網(wǎng)絡(luò)通訊的具體實(shí)例。闡述了Java AIO 的基本原理,示范了其實(shí)現(xiàn)的具體方式。

猜你喜歡
網(wǎng)絡(luò)通訊監(jiān)聽(tīng)內(nèi)核
萬(wàn)物皆可IP的時(shí)代,我們當(dāng)夯實(shí)的IP內(nèi)核是什么?
強(qiáng)化『高新』內(nèi)核 打造農(nóng)業(yè)『硅谷』
千元監(jiān)聽(tīng)風(fēng)格Hi-Fi箱新選擇 Summer audio A-401
基于嵌入式Linux內(nèi)核的自恢復(fù)設(shè)計(jì)
Linux內(nèi)核mmap保護(hù)機(jī)制研究
網(wǎng)絡(luò)監(jiān)聽(tīng)的防范措施
電子制作(2017年20期)2017-04-26 06:58:02
關(guān)于網(wǎng)絡(luò)通訊中信息安全的保障研究
應(yīng)召反潛時(shí)無(wú)人機(jī)監(jiān)聽(tīng)航路的規(guī)劃
別克君越高速網(wǎng)絡(luò)通訊異常
基于現(xiàn)代網(wǎng)絡(luò)通訊工具的中醫(yī)診斷學(xué)教學(xué)實(shí)踐與探索
闽侯县| 佛坪县| 阳信县| 长春市| 玉山县| 滕州市| 庐江县| 饶河县| 山阴县| 陕西省| 东阳市| 志丹县| 内黄县| 宕昌县| 武夷山市| 和田市| 光山县| 呈贡县| 虹口区| 长垣县| 老河口市| 海南省| 驻马店市| 商河县| 洪泽县| 定州市| 称多县| 新宁县| 镇江市| 中西区| 德庆县| 海城市| 买车| 平邑县| 苍南县| 黄龙县| 浦城县| 水富县| 成安县| 松桃| 宿松县|