傳統的socket之BIO到僞異步IO到NIO最後到AIO簡介

關鍵字:NIO, IO,BIO,AIO的簡介以及演變原因

本人對nio確實也瞭解的不深,此文只是簡介

代碼在 https://github.com/zhaikaishun/NettyTutorial 下的socket01

傳統的BIO通信:同步阻塞模式

看圖,侵刪

bio通信模型圖

傳統的模式是BIO模式,是同步阻塞的,直接看下面這個例子吧。
Server端

        ServerSocket server = null; //bio, 使用一個ServerSocket類進行socket傳輸
        int PROT = 9999;
        try {
            server = new ServerSocket(PROT);
            System.out.println(" server start .. ");
            //進行阻塞,
            while (true){
                Socket socket = server.accept();//!!直到client建立socket連接的時候,纔會走下面的操作
                System.out.println("client建立scoket連接後才走這裏");
                //新建一個線程執行客戶端的任務
                new Thread(new ServerHandler(socket)).start();
            }

        //下面的不用看了
        } catch (Exception e)
....

ServerHandler處理類,主要用來輸出,這裏停留5000毫秒

in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
out = new PrintWriter(this.socket.getOutputStream(), true);
String body = null;
while((body = in.readLine())!=null){
    System.out.println("Server :" + body);
    Thread.sleep(5000);
    //給客戶端響應
    out.println("這是服務器端回送響的應數據.");
}

Client端

String ADDRESS = "127.0.0.1";
int PORT = 9999;

socket = new Socket(ADDRESS, PORT);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);

//向服務器端發送數據
out.println("接收到客戶端的請求數據...");
System.out.println("執行完這一句後,下面的in.readLine是阻塞的");
//in.readLine();是阻塞的,必須等待服務器端完成之後才能讀的到
String response = in.readLine();
System.out.println("Client: " + response);

分析NIO的模式, 先運行Server,Server輸出

 server start .. 

再運行client,client輸出

執行完這一句後,下面的in.readLine是阻塞的  

Server端輸出

client建立scoket連接後才走這裏
Server :接收到客戶端的請求數據...

5秒後再運行client輸出:

Client: 這是服務器端回送響的應數據.

總結: Server端的 Socket socket = server.accept(); 會造成阻塞,直到client建立連接的時候纔會執行後面的操作
Client端的: String response = in.readLine(); 也會造成阻塞,直到Server.accept響應後才能執行後面的操作
而且,每個Client都會在Server端建立一個線程,如果client併發較多的時候,Server服務器會承受不住從而導致癱瘓

僞異步IO的模式

看圖:侵刪
僞異步IO
在沒有實現NIO之前的一種模式
直接看例子,和上面那個差不錯,只不過Server端使用了線程池而已,將客戶端的socket封裝成一個task任務,這樣client併發多的時候,就會通過等待來執行,不會讓線程一下子起的太多,下面就只見到記錄一下Server端的代碼,其他代碼和上面的例子一致
Server端

int PORT = 9999;
ServerSocket server = null;
BufferedReader in = null;
PrintWriter out = null;
try {
    server = new ServerSocket(PORT);
    System.out.println("server start");
    Socket socket = null; 
    HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 1000);  //其實整體都是一樣,只不過這裏再加了一個線程池而已
    while(true){
        socket = server.accept();
        executorPool.execute(new ServerHandler(socket));
    }

} catch (Exception e) 

線程池封裝類HandlerExecutorPool

public class HandlerExecutorPool {

    private ExecutorService executor;
    public HandlerExecutorPool(int maxPoolSize, int queueSize){
        this.executor = new ThreadPoolExecutor(
                Runtime.getRuntime().availableProcessors(),
                maxPoolSize, 
                120L, 
                TimeUnit.SECONDS,
                new ArrayBlockingQueue<Runnable>(queueSize));
    }

    public void execute(Runnable task){
        this.executor.execute(task);
    }
}

NIO和IO的關係與區別:

阻塞概念:應用程序在獲取網絡數據的時候,如果網絡傳輸很慢,那麼程序就一直等着,直到傳輸完畢爲止
非阻塞:應用程序直接可以獲取已經準備好的數據,無需等待

NIO: 同步非阻塞

同步:應用程序直接參與io讀寫,程序會直接阻塞到某個方法上
異步: 所有的io都交給操作系統,當操作系統完成了io的操作的時候,會給我們應用程序發通知

同步異步說的是Server服務端的執行方式
阻塞說的是技術,接受數據的方式,狀態(IO,NIO)

NIO

幾大概念
buffer
channel
selecter 就是一個插座
nio基本圖

buffer

使用一下flip方法復位,位置纔回到0,但是後面空的會清零(比較好),不建議使用posistion的方法進行處理
具體的buffer操作案例,這裏也不太想記了(nio真的直接用起來非常少), 代碼都在kaishun.nio.test.TestBuffer 類下

AIO

異步非阻塞: 我這裏也沒有細看,暫時也不是很明白,TODO zhaikaishun 2017-06-10[有時間吧]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章