• <noscript id="e0iig"><kbd id="e0iig"></kbd></noscript>
  • <td id="e0iig"></td>
  • <option id="e0iig"></option>
  • <noscript id="e0iig"><source id="e0iig"></source></noscript>
  • Netty--BIO

    標簽: Netty  BIO  

    I/O模型

    • I/O 模型簡單的理解:就是用什么樣的通道進行數據的發送和接收,很大程度上決定了程序通信的性能
    • Java 共支持 3 種網絡編程模型/IO 模式:BIO、NIO、AIO
    • Java BIO : 同步并阻塞(傳統阻塞型),服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器 端就需要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷

    在這里插入圖片描述

    • Java NIO : 同步非阻塞,服務器實現模式為一個線程處理多個請求(連接),即客戶端發送的連接請求都會注 冊到多路復用器上,多路復用器輪詢到連接有 I/O 請求就進行處理

    在這里插入圖片描述

    • Java AIO(NIO.2) : 異步非阻塞,AIO 引入異步通道的概念,采用了 Proactor 模式,簡化了程序編寫,有效 的請求才啟動線程,它的特點是先由操作系統完成后才通知服務端程序啟動線程去處理,一般適用于連接數較 多且連接時間較長的應用

    BIO、NIO、AIO 適用場景分析

    • BIO 方式適用于連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,并發局限于應用中,JDK1.4
      以前的唯一選擇,但程序簡單易理解。

    • NIO 方式適用于連接數目多且連接比較短(輕操作)的架構,比如聊天服務器,彈幕系統,服務器間通訊等。
      編程比較復雜,JDK1.4 開始支持。

    • AIO 方式使用于連接數目多且連接比較長(重操作)的架構,比如相冊服務器,充分調用 OS 參與并發操作,
      編程比較復雜,JDK7 開始支持。

    BIO

    • Java BIO 就是傳統的 java io 編程,其相關的類和接口在 java.io
    • BIO(blocking I/O) : 同步阻塞,服務器實現模式為一個連接一個線程,即客戶端有連接請求時服務器端就需 要啟動一個線程進行處理,如果這個連接不做任何事情會造成不必要的線程開銷,可以通過線程池機制改善(實 現多個客戶連接服務器)。 【后有應用實例】
    • BIO 方式適用于連接數目比較小且固定的架構,這種方式對服務器資源要求比較高,并發局限于應用中,JDK1.4 以前的唯一選擇,程序簡單易理解

    BIO的工作機制

    在這里插入圖片描述

    1. 服務器端啟動一個ServerSocket
    2. 客戶端啟動Socket對服務器進行通信,默認情況下服務器端需要對每個客戶建立一個線程與之通訊
    3. 客戶端發出請求后, 先咨詢服務器是否有線程響應,如果沒有則會等待,或者被拒絕
    4. 如果有響應,客戶端線程會等待請求結束后,在繼續執行

    實例

    1. 使用BIO模型編寫一個服務器端,監聽6666端口,當有客戶端連接時,就啟動一個線程與之通訊。
    2. 要求使用線程池機制改善,可以連接多個客戶端.
    3. 服務器端可以接收客戶端發送的數據(telnet 方式即可)。
    4. 代碼演示
    package com.atguigu.bio;
    
    import java.io.InputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    
    public class BIOServer {
        public static void main(String[] args) throws Exception {
    
            //線程池機制
    
            //思路
            //1. 創建一個線程池
            //2. 如果有客戶端連接,就創建一個線程,與之通訊(單獨寫一個方法)
    
            ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
    
            //創建ServerSocket
            ServerSocket serverSocket = new ServerSocket(6666);
    
            System.out.println("服務器啟動了");
    
            while (true) {
    
                System.out.println("線程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
                //監聽,等待客戶端連接
                System.out.println("等待連接....");
                final Socket socket = serverSocket.accept();
                System.out.println("連接到一個客戶端");
    
                //就創建一個線程,與之通訊(單獨寫一個方法)
                newCachedThreadPool.execute(new Runnable() {
                    public void run() { //我們重寫
                        //可以和客戶端通訊
                        handler(socket);
                    }
                });
    
            }
    
    
        }
    
        //編寫一個handler方法,和客戶端通訊
        public static void handler(Socket socket) {
    
            try {
                System.out.println("線程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
                byte[] bytes = new byte[1024];
                //通過socket 獲取輸入流
                InputStream inputStream = socket.getInputStream();
    
                //循環的讀取客戶端發送的數據
                while (true) {
    
                    System.out.println("線程信息 id =" + Thread.currentThread().getId() + " 名字=" + Thread.currentThread().getName());
    
                    System.out.println("read....");
                   int read =  inputStream.read(bytes);
                   if(read != -1) {
                       System.out.println(new String(bytes, 0, read
                       )); //輸出客戶端發送的數據
                   } else {
                       break;
                   }
                }
    
    
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                System.out.println("關閉和client的連接");
                try {
                    socket.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
    
            }
        }
    }
    

    BIO存在的問題

    • 每個請求都需要創建獨立的線程,與對應的客戶端進行數據 Read,業務處理,數據 Write 。
    • 當并發數較大時,需要創建大量線程來處理連接,系統資源占用較大。
    • 連接建立后,如果當前線程暫時沒有數據可讀,則線程就阻塞在 Read 操作上,造成線程資源浪費
    版權聲明:本文為cold___play原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。
    本文鏈接:https://blog.csdn.net/cold___play/article/details/104324846

    智能推薦

    劍指Offer39-調整數組順序使奇數位于偶數前面

    一開始想著用冒泡排序的方法來做,但是bug還是很多,后來看了評論區答案,發現直接空間換時間是最簡單的,而且和快排的寫法是類似的。...

    【一只蒟蒻的刷題歷程】【藍橋杯】歷屆試題 九宮重排 (八數碼問題:BFS+集合set)

    資源限制 時間限制:1.0s 內存限制:256.0MB 問題描述 如下面第一個圖的九宮格中,放著 1~8 的數字卡片,還有一個格子空著。與空格子相鄰的格子中的卡片可以移動到空格中。經過若干次移動,可以形成第二個圖所示的局面。 我們把第一個圖的局面記為:12345678. 把第二個圖的局面記為:123.46758 顯然是按從上到下,從左到右的順序記錄數字,空格記為句點。 本題目的任務是已知九宮的初態...

    dataV組件容器寬高發生變化后,組件不會自適應解決方法

    項目中需要大屏幕數據展示,于是使用了dataV組件,但是使用是發現拖動瀏覽器邊框,dataV組件顯示異常,如圖: 于是查了官網,官網的解釋如下:   于是按照官網的意思編寫代碼: 于是可以自適應了...

    CSS3干貨10:如何做一個板塊標題水平線左邊帶顏色效果

    很多網站在設計欄目標題的時候,喜歡用下劃線分開欄目標題和內容部分。 而且線條左邊的部分往往還有顏色,且這個顏色跟標題的文字長短保持一致。效果如圖所示: 這種效果其實很簡單。 我這里給大家推薦兩種方式: 假定我們的標題部分 HTML 結構如下: 方式一:利用下邊框。灰色部分是 h1 的下邊框,藍色部分是 span 標簽的下邊框。 h1 的高度為 40px,span 也設置它的高度為 40px。這樣,...

    拜師————python基礎入門——程序的構成,對象,引用,棧內存和堆內存,標識符命名規則——day4

    第九節課:任務9:009.程序的構成 Python程序的構成,一個程序是由什么構成的 1.python程序由模塊組成 , 一個模塊對應一個python源文件,(文件后綴名.py) 2.模塊由語句構成 運行程序時,安裝模塊中語句的順序依次執行。 代碼的組織和縮進 “龜叔”在設計python時,直接通過縮進來組織代碼 縮進時,幾個空格都是允許的,但是空格數必須統一,我們通常用四...

    猜你喜歡

    spark 總結 算子篇

    1、創建工程 在這里添加 spark core包,添加bulid 插件。 算子總結 map 算子 主要是做數據結構的轉換,數據條數不變。 mapPartitions(func) 對分區數據進行轉換。將某一個分區的所有數據拿過來形成一個可迭代的集合要求 返回可迭代的集合。提高效率會使用它。 應用場景: 只對分區內數據進行數據。缺點是不釋放,可能導致oom。 當內存空間較大的時候建議使用 mapPar...

    淺析Redis復制過程

    文章目錄 摘要 復制 當 Master 關閉持久化時,復制的安全性 復制的工作原理 配置 只讀 Slave 寫入Master Slave如何處理key的過期 參考 摘要 Redis默認使用異步復制,其特點是低延遲和高性能。異步復制就意味著在故障轉移期間,有丟失數據的風險。你可以參考Redis 集群文檔,了解關于高可用性和故障轉移的信息,本文主要討論Redis 復制功能的基本特性。 復制 在 Red...

    OpenStack(kilo)界面dashboard的二次開發(二)-增加PanelGroup

    上一博文開了一個頭,簡單的總結了下代碼結構及Panel的增加,這一篇對Panelgroup的增加做一個詳細的總結。 增加Panelgroup Panelgroup字面意思很好理解就是panel組,在openstack的界面中就是多個panel的集合。上一次的代碼分析中其實已經有了對PanelGroup的簡單介紹,這次就看看如何增加panelgroup。 這次直接查看Admin(管理員)Dashbo...

    負載均衡下多臺服務器代碼同步 rsync

    公司現在的服務器架構采用的是阿里的SLB(負載均衡)   現在是有一個負載均衡對應兩臺ECS實例  負載均衡就是當有客戶端的請求的時候 它會對后端server的服務器進行健康檢查并根據設置的權重去分配請求,好處就是當其中某臺服務器宕機不會造成損失。起到了容災效果 現在的需求: 1、現在就是后端的server服務器都布置好了,代碼怎么同步到每臺服務器上,不可能在每臺服務器都進行git pu...

    System.arraycopy的用法

    方法定義 參數: src:源數組 srcPos:源數組起始位置 dest:目的數組 destPos:目的數組起始位置 length:復制數組的長度 示意圖: 圖中,將src的一段長為length的子數組復制到dest,同時覆蓋dest中這段的元素。 從圖可知: 如果srcPos + length > src的長度,報IndexOutOfBoundsException 如果destPos + ...

    精品国产乱码久久久久久蜜桃不卡