04-NIO Channel

NIO Channel

  • Channel (java.nio.channels.Channel) 是 NIO 的三個核心組件之一,Channel 在NIO中代表通道,在JDK中是一個接口。

一、Channel和流

  • Channel 可以是雙向的,既可以通過Channel讀數據,也可以寫數據,流的話要麼是輸入流,要麼是輸出流
  • 不能直接通過 Channel 讀寫數據,必須通過buffer操作,程序通過Buffer間接的和Channel打交道,程序永遠不能繞過buffer直接操作Channel,而流是可以直接讀寫的
  • Channel的讀寫可以是非阻塞的,而流是阻塞的

二、Channel的主要實現類

實現類 作用場景
SocketChannel 客戶端用來發起 TCP連接的 的 Channel
ServerSocketChannel 服務端用於監聽客戶端TCP連接的Channel,每接受到一個連接,則會創建一個SocketChannel
DatagramChannel 通過 UDP 讀寫數據的 Channel
FileChannel 從文件讀寫數據的 Channel

在 Netty 中主要涉及到的是 SocketChannel 和 ServerSocketChannel ,下面給出這兩個的繼承圖,比較類似:

在這裏插入圖片描述

在這裏插入圖片描述

三、從Socket到Channel

  • 最初的網絡編程最熟悉的類是 Socket 和 ServerSocket,那麼 Socket 和 ServerSocket VS SocketChannel 和 ServerSocketChannel ,這兩組類之間的區別和聯繫是什麼?

3.1 Socket和ServerSocket

  • Socket 和 ServerSocke 是對應的,分別對應客戶端和服務端,它們是 java.net 下面實現 Socket 通信的類,只支持阻塞通信(或者自己實現非阻塞通信),通常在 ServerSocket 實現的服務端是爲每一個客戶端分配一個線程(或者線程池),由此能夠支持的客戶端數量有限。
  • 在阻塞IO的通信中我們就是使用這兩個類,在文章: 03-BIO、NIO到Netty 的BIO示例中有給出,核心僞代碼如下:
客戶端:
{
    Socket socket = new Socket(IP, PORT);

    //後續數據讀寫:
    socket.getOutputStream()
    socket.getInputStream()    
}


服務端:
{
    ServerSocket serverSocket = new ServerSocket(PORT);
    while (true) {
        Socket socket = serverSocket.accept();

        //線程池處理連接
        threadPool.execute(new ServerHandler(socket));
    }    
}
  • Socket:可以理解爲客戶端與服務端的一個連接,比如客戶端 Socket socket=new Socket(ip,port);其中 socket 這個 Socket 對象就代表客戶端和對應ip端口的一個連接;
  • ServerSocket:可以理解爲服務端等待客戶端連接的一個Socket對象,比如服務端 ServerSocket serverSocket = new ServerSocket(port);其中 serverSocket 代表服務端監聽在 port 的一個 Socket,這裏並不代表一個連接,僅僅代表一個服務的監聽,ServerSocket收到連接請求之後通過 accept方法可以打開一個Socket對象,與客戶端進行通信。

3.2 SocketChannel和ServerSocketChannel

  • SocketChannel 和 ServerSocketChannel 是對應的,分別對應客戶端和服務端,他們是 java.nio 下面實現通信的類,支持異步通信(通過參數配置)
  • 在NIO的通信中我們就是使用這兩個類,在文章: 03-BIO、NIO到Netty 的NIO示例中有給出,核心僞代碼如下:
{
     Selector selector = Selector.open();
     ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
     serverSocketChannel.configureBlocking(false);
     serverSocketChannel.socket().bind(new InetSocketAddress(port));
     serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
     
     while(true){
          selector.select();
          Set<SelectionKey> selectionKeys = selector.selectedKeys();
          //處理事件      
    }
}
  • SocketChannel:可以理解爲客戶端與服務端的一個Tcp Channel通道,類比於Socket
  • ServerSocketChannel:可以綁定端口等待監聽,類比於 ServerSocket,ServerSocketChannel的accept方法會返回一個 SockerChannel
  • SocketChannel和ServerSocketChannel的使用需要結合 Selector 組件,通過Selector 實現少量線程管理大量連接。

3.3 聯繫

  • 下面圖是這四個類大致的關係,我們看到從功能上來看 Socket 和 SocketChannel很類似,SocketChannel 和 ServerSocketChannel很類似,但是Channel提供了非阻塞的通信模式,因此可以簡單地認爲Channel是對Socket的升級。而且通過getChannel()方法和socket()方法,他們之間可以相互轉換。

在這裏插入圖片描述

  • 通信時,服務器必須先建立 ServerSocket 或者 ServerSocketChannel 監聽並等待客戶端的連接,客戶端必須建立相對應的 Socket 或者 SocketChannel 來與服務器建立連接,服務器在接受到客戶端的連接受,會生成一個 Socket 或者 SocketChannel 與此客戶端通信,注意重新生成的連接所使用的端口與監聽的端口是不一樣的。

四、Netty Channel

  • 前面描述的是 java.nio.channels.Channel,是JDK NIO 中的 Channel,和 Netty中的Channel還不一樣,Netty中自己定義了 io.netty.channel.Channel,Netty的Channel 後續專門再分析,這裏只提一下,在Netty中 io.netty.channel.Channel 接口的實現類 有些封裝了 JDK的Channel,比如在 NioServerSocketChannel 中就封裝了 NIO 中的ServerSocketChannel,SocketChannel和SelectionKey等組件,因此可以認爲Netty重新定義了一套Channel接口以及相關的繼承體系可以更好的組織類之間的關係,提供統一的API,但是其底層最終還是會用到JDK NIO的相關實現,最底層的通信類還是用的JDK的。

參考

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