文章目錄
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的。