Java網絡編程-深入理解BIO、NIO

深入理解BIO與NIO

BIO

BIO 為 Blocked-IO(阻塞 IO),在 JDK1.4 之前建立網絡連接時,只能使用 BIO

使用 BIO 時,服務端會對客戶端的每個請求都建立一個線程進行處理,客戶端向服務端發送請求后,先咨詢服務端是否有線程響應,如果沒有就會等待或者被拒絕

BIO 基本使用代碼:

服務端:

public class TCPServer {public static void main(String[] args) throws Exception {// 1.創建ServerSocket對象System.out.println("服務端 啟動....");System.out.println("初始化端口 7777 ");ServerSocket ss = new ServerSocket(7777); //端口號while (true) {// 2.監聽客戶端Socket s = ss.accept(); //阻塞// 3.從連接中取出輸入流來接收消息InputStream is = s.getInputStream(); //阻塞byte[] b = new byte[10];is.read(b);String clientIP = s.getInetAddress().getHostAddress();System.out.println(clientIP + "說:" + new String(b).trim());// 4.從連接中取出輸出流并回話OutputStream os = s.getOutputStream();os.write("服務端回復".getBytes());// 5.關閉s.close();}}
}

客戶端:

public class TCPClient {public static void main(String[] args) throws Exception {while (true) {// 1.創建Socket對象Socket s = new Socket("127.0.0.1", 7777);// 2.從連接中取出輸出流并發消息OutputStream os = s.getOutputStream();System.out.println("請輸入:");Scanner sc = new Scanner(System.in);String msg = sc.nextLine();os.write(msg.getBytes());// 3.從連接中取出輸入流并接收回話InputStream is = s.getInputStream(); //阻塞byte[] b = new byte[20];is.read(b);System.out.println("客戶端發送消息:" + new String(b).trim());// 4.關閉s.close();}}
}

BIO 缺點:

  • Server 端會為客戶端的每一個連接請求都創建一個新的線程進行處理,如果客戶端連接請求數量太多,則會創建大量線程

NIO

從 JDK1.4 開始,Java 提供了一系列改進的輸入/輸出的新特性,被統稱為 NIO(即 New IO),NIO 彌補了 BIO 的不足,在服務端不需要為客戶端大量的請求而建立大量的處理線程,只需要用很少的線程就可以處理很多客戶端請求

NIO 和 BIO 有著相同的目的和作用,但是它們的實現方式完全不同;

  • BIO 以流的方式處理數據,而 NIO 以塊的方式處理數據,塊 IO 的效率比流 IO 高很多。
  • NIO 是非阻塞式的,這一點跟 BIO 也很不相同,使用它可以提供非阻塞式的高伸縮性網絡。

NIO 有三大核心部分

  • Channel通道
  • Buffer緩沖區
  • Selector選擇器

使用 NIO 時,數據是基于 ChannelBuffer 進行操作的,數據從 Channel 被讀取到 Buffer 或者相反,Selector 用于監聽多個 Channel 通道的事件(連接事件、讀寫事件),通過 Selector 就可以實現單個線程來監聽多個客戶端通道

NIO 中的 Channel 用來建立到目標的一個連接,在 BIO 中流是單向的,例如 FileInputStream 只能進行讀取操作,而在 NIO 中 Channel 是雙向的,既可以讀也可以寫

NIO 工作流程圖如下:Server 端通過單線程來監聽多個客戶端 Channel 通道中的事件并進行處理

外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳

NIO 使用示例

服務端:

public class NIOServer {public static void main(String[] args) throws Exception {// 1. 開啟一個ServerSocketChannel通道ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();// 2. 開啟一個Selector選擇器Selector selector = Selector.open();// 3. 綁定端口號8888System.out.println("服務端 啟動....");System.out.println("初始化端口 8888 ");serverSocketChannel.bind(new InetSocketAddress(8888));// 4. 配置非阻塞方式serverSocketChannel.configureBlocking(false);// 5. Selector選擇器注冊ServerSocketChannel通道,綁定連接操作serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 6. 循環執行:監聽連接事件及讀取數據操作while (true) {// 6.1 監控客戶端連接:selecto.select()方法返回的是客戶端的通道數,如果為0,則說明沒有客戶端連接。if (selector.select(2000) == 0) {System.out.println("服務端等待客戶端連接中~");continue;}// 6.2 得到SelectionKey,判斷通道里的事件Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();// 遍歷所有SelectionKeywhile (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();// 客戶端連接請求事件if (key.isAcceptable()) {System.out.println("服務端處理客戶端連接事件:OP_ACCEPT");SocketChannel socketChannel = serverSocketChannel.accept();socketChannel.configureBlocking(false);// 服務端建立與客戶端之間的連接通道 SocketChannel,并且將該通道注冊到 Selector 中,監聽該通道的讀事件socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));}// 讀取客戶端數據事件if (key.isReadable()) {// 數據在通道中,先拿到通道SocketChannel channel = (SocketChannel) key.channel();// 取到一個緩沖區,nio讀寫數據都是基于緩沖區。ByteBuffer buffer = (ByteBuffer) key.attachment();// 從通道中將客戶端發來的數據讀到緩沖區channel.read(buffer);System.out.println("客戶端數據長度:" + buffer.array().length);System.out.println("客戶端發來數據:" + new String(buffer.array()));}//  6.3 手動從集合中移除當前key,防止重復處理keyIterator.remove();}}}
}

客戶端:

public class NIOClient {public static void main(String[] args) throws Exception {// 1. 得到一個網絡通道SocketChannel channel = SocketChannel.open();// 2. 設置非阻塞方式channel.configureBlocking(false);// 3. 提供服務器端的IP地址和端口號InetSocketAddress address = new InetSocketAddress("127.0.0.1", 8888);// 4. 連接服務器端,如果用connect()方法連接服務器不成功,則用finishConnect()方法進行連接if (!channel.connect(address)) {// 因為接需要花時間,所以用while一直去嘗試連接。在連接服務端時還可以做別的事,體現非阻塞。while (!channel.finishConnect()) {// nio 作為非阻塞式的優勢,如果服務器沒有響應(不啟動服務端),客戶端不會阻塞,最后會報錯,客戶端嘗試連接服務器連不上。System.out.println("客戶端等待連接建立時,執行其他任務~");}}// 5. 得到一個緩沖區并存入數據String msg = "客戶端發送消息:hello";ByteBuffer writeBuf = ByteBuffer.wrap(msg.getBytes());// 6. 發送數據channel.write(writeBuf);// 阻止客戶端停止,否則服務端也會停止。System.in.read();}
}

AIO

JDK 7 引入了 Asynchronous IO,即 AIO,叫做異步不阻塞的 IO,也可以叫做 NIO2

在進行 IO 編程中,常用到兩種模式:Reactor模式 和 Proactor 模式

  • NIO采用 Reactor 模式,當有事件觸發時,服務器端得到通知,進行相應的處理
  • AIO采用 Proactor 模式,引入異步通道的概念,簡化了程序編寫,一個有效的請求才啟動一個線程,它的特點是先由操作系統完成后,才通知服務端程序啟動線程去處理,一般適用于連接數較多且連接時間較長的應用

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/208375.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/208375.shtml
英文地址,請注明出處:http://en.pswp.cn/news/208375.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

3接上篇 我的自定義GPTs的改進優化 與物理世界連接成功 GPTs的創建與使用定義和執行特定任務的功能模塊 通過API與外部系統或服務的交互

https://blog.csdn.net/chenhao0568/article/details/134875067?spm1001.2014.3001.5502 從服務器日志里看到請求多了一個“location” 23.102.140.123 - - [08/Dec/2023:14:02:20 0800] "GET /getWeather.php?location&locationNewYork HTTP/1.1" 200 337 &…

2024年甘肅省職業院校技能大賽信息安全管理與評估賽項一階段樣題一

2024年甘肅省職業院校技能大賽高職學生組電子與信息大類信息安全管理與評估賽項樣題一 競賽需要完成三個階段的任務&#xff0c;分別完成三個模塊&#xff0c;總分共計 1000分。三個模塊內容和分值分別是&#xff1a; 1.第一階段&#xff1a;模塊一 網絡平臺搭建與設備安全防…

【K8S】微服務不香了?單體化改造悄然興起!!

微服務一直以來是服務治理的基本盤之一,落地到云原生上,往往是每個 K8s pods 部署一個服務,獨立迭代、獨立運維。 但是在快速部署的時候,有時候,我們可能需要一些宏服務的優勢。有沒有一種方法,能夠 “既要又要” 呢?本文基于 tRPC-Go 服務,提出并最終實踐了一種經驗證…

從互聯網到云計算再到 AI 原生,百度智能云數據庫的演進

1 數據庫行業發展概述 如果說今年科技圈什么最火&#xff0c;我估計大家會毫不猶豫選擇 ChatGPT。ChatGPT 是 2022 年 11 月 30 日由 OpenAI 發布的聊天應用。它創造了有史以來用戶增長最快的紀錄&#xff1a;自 11 月 30 日發布起&#xff0c;5 天就擁有了 100 萬活躍用戶&am…

靜態HTTP和動態HTTP的混合使用:最佳實踐

在當今的互聯網環境中&#xff0c;靜態HTTP和動態HTTP各有其優勢和局限。靜態HTTP具有速度快、安全性高和易于維護的特點&#xff0c;而動態HTTP則能夠實現動態交互和處理大量動態數據。為了充分利用兩者的優勢&#xff0c;越來越多的網站開始采用靜態HTTP和動態HTTP混合使用的…

計算機的存儲規則

計算機存儲 計算機采用二進制來存儲數據和程序 原因主要有&#xff1a; (1) 物理上容易實現 (2) 運算規則非常簡單 (3) 可靠性強 (4) 易于實現邏輯運算和邏輯判斷 計算機中存儲器的分類及特點 根據存儲器在計算機系統中所起的作用 分為內存儲器和外存儲器 (1) 內存用來…

大數據畢業設計之前端02:架構布局和aside的設計

前言 上一篇主要講了我學習前端的一個經歷&#xff0c;以及為什么選擇BuildAdmin作為深入前端學習的原因.同事也大致聊了一下學習前端需要使用哪些技術棧。 本篇文章來拆解一下BuildAdmin的前端代碼結構&#xff0c;和布局實現的細節。 前端代碼結構 必須先了解項目的結構&…

leetcode每日一題37

92.反轉鏈表II 這道題需要1.找到位置left 2.在位置left開始&#xff0c;一前一后兩個指針反轉鏈表&#xff0c;代碼同206.反轉鏈表&#xff0c;直到后一個指針指向right 3.把反轉后的頭節點鏈接到left-1后面&#xff0c;把反轉后的鏈表尾節點指向right1位置的節點 因為可能會反…

數據結構——二叉樹的鏈式結構

個人主頁&#xff1a;日刷百題 系列專欄&#xff1a;〖C語言小游戲〗〖Linux〗〖數據結構〗 〖C語言〗 &#x1f30e;歡迎各位→點贊&#x1f44d;收藏??留言&#x1f4dd; ? 一、二叉樹的創建 這里我們使用先序遍歷的思想來創建二叉樹&#xff0c;這里的內容對于剛接觸二…

iClient3D 加載天地圖服務

1 對國家天地圖&#xff0c;通過TiandituImageryProvider影像服務提供者加載地圖&#xff1b; var TiandituimageryLayernew Cesium.TiandituImageryProvider({ mapStyle: Cesium.TiandituMapsStyle[value],token: "4a00a1dc5387b8ed8adba3374bd87e5e"})viewer.imag…

nginx 的概念、高并發處理及詳細參數配置

NGINX是一個開源的高性能Web服務器&#xff0c;負載均衡器和反向代理服務器。它特別適用于高并發的Web應用&#xff0c;能夠有效地處理數千并發連接&#xff0c;同時具備低資源消耗和高性能的特點。在這里&#xff0c;我將重點介紹NGINX的高并發處理能力和參數配置。 高并發處…

云原生(Cloud Native)——概念,技術,背景,優缺點,實踐例子

云原生&#xff08;Cloud Native&#xff09;是一種構建和運行應用程序的方法&#xff0c;這些應用程序充分利用云計算的優勢。云原生應用程序通常設計為在現代、動態的環境中運行&#xff0c;如公共云、私有云和混合云。這種方法強調微服務架構、容器化、自動化、易于管理和可…

QT 信號與槽 connect 三種寫法

先看下示例&#xff1a; QPushButton *btn new QPushButton;// 方式一&#xff1a;老式寫法connect(btn, SIGNAL(clicked()), this, SLOT(close()));// 方式二&#xff1a;Qt5后新寫法connect(btn, &QPushButton::clicked, this, &MainWindow::close);// 方式三&#…

Word插件-好用的插件-一鍵設置字體--大珩助手

常用字體 整理了論文、公文常用字體 整理了常用的論文字體&#xff0c;可一鍵設置當前節或選擇的文字的字體 字體設置 包含字體選擇、字體顏色 特殊格式 包含首字下沉、段落分欄、統一寬度、雙行合一、上標切換、下標切換、轉為全角、轉為半角、挖詞填空、當前日期、大寫金…

LabVIEW開發遠程結構健康監測系統

LabVIEW開發遠程結構健康監測系統 工程師依賴于振動監測來評估建筑物、橋梁和其他大型結構的完整性。傳統的振動監測工具在數據收集上存在限制&#xff0c;無法長時間收集高保真波形。隨著內存存儲、處理器速度和寬帶無線通信技術的進步&#xff0c;出現了對能夠長時間收集并實…

Navicat 技術指引 | 適用于 GaussDB 分布式的查詢功能

Navicat Premium&#xff08;16.3.3 Windows 版或以上&#xff09;正式支持 GaussDB 分布式數據庫。GaussDB 分布式模式更適合對系統可用性和數據處理能力要求較高的場景。Navicat 工具不僅提供可視化數據查看和編輯功能&#xff0c;還提供強大的高階功能&#xff08;如模型、結…

深入了解對象與內置構造函數

1. 深入對象 1.1 創建對象的三種方式 1.2 構造函數 語法約定&#xff1a; 總結 構造函數可以快速創建多個對象大寫字母開頭的函數使用new關鍵字將對象實例化構造函數不需要返回值自動返回新的對象 new實例化的執行過程 創建空對象this指向對象執行代碼&#xff0c;追加新…

使用wire重構商品微服務

一.wire簡介 Wire 是一個輕巧的Golang依賴注入工具。它由Go Cloud團隊開發&#xff0c;通過自動生成代碼的方式在編譯期完成依賴注入。 依賴注入是保持軟件 “低耦合、易維護” 的重要設計準則之一。 此準則被廣泛應用在各種開發平臺之中&#xff0c;有很多與之相關的優秀工…

使用pyftpdlib組件實現FTP文件共享

目錄 一、引言 二、技術背景 三、實現邏輯 1、創建FTP服務器&#xff1a; 2、實現文件共享&#xff1a; 3、設置用戶權限&#xff1a; 4、處理異常&#xff1a; 5、優化與擴展&#xff1a; 四、代碼實現 五、測試與評估 測試用例&#xff1a; 評估方法&#xff1a;…

React/Vue/Svelte 前端項目中開始使用TailwindCSS

背景 TailwindCSS 近年來在前端圈非常流行&#xff0c;它擺脫了原有的CSS限制&#xff0c;以靈活實用為賣點&#xff0c;用戶通過各種class組合即可構建出漂亮的用戶界面。對于初學者而言&#xff0c;可能需要一些上手成本&#xff0c;一旦掌握實用技巧后&#xff0c;Tailwind…