簡介
channel是連線客戶端和伺服器端的橋樑,在netty中我們最常用的就是NIO,一般和NioEventLoopGroup配套使用的就是NioServerSocketChannel和NioSocketChannel,如果是UDP協議,那麼配套使用的就是NioDatagramChannel,如果是別的協議還有其他不同的Channel型別。
這些不同channel型別有什麼區別呢?一個直觀的感覺就是不同的channel和channel連線使用的協議有關係,不同的channel可能適配了不同的連線協議。
事實到底是不是如此呢?在netty的內部實現中到底有多少種channel呢?今天一起來探討一下。
ServerChannel和它的型別
雖然ServerChannel繼承自Channel,但是ServerChannel本身並沒有新增任何新的方法:
public interface ServerChannel extends Channel {
}
所以對ServerChannel和Channel來說都可以看做是Channel,他們只是語義上有區別。
但是因為ServerChannel繼承自Channel,所以相對的ServerChannel的分類和實現要比Channel要少。所以我們先以ServerChannel為例進行講解。
ServerChannel的實現也有很多,我們以Abstract*開頭的實現為例,下面是他們的繼承關係:
從上圖我們可以看出,ServerChannel有六個抽象類實現,分別是AbstractEpollServerChannel,AbstractKQueueServerChannel,AbstractServerChannel,ServerSocketChannel,SctpServerChannel和ServerDomainSocketChannel。
其中前面三個抽象類同時繼承自AbstractChannel。
Epoll和Kqueue
Epoll和Kqueue是兩個獨特的依賴於特定平臺的NIO協議,其中epoll只在linux平臺才支援,而kQueue則在FreeBSD、NetBSD、OpenBSD、macOS 等作業系統支援。
我們來看下AbstractEpollServerChannel的建構函式:
protected AbstractEpollServerChannel(int fd) {
this(new LinuxSocket(fd), false);
}
AbstractEpollServerChannel(LinuxSocket fd) {
this(fd, isSoErrorZero(fd));
}
AbstractEpollServerChannel(LinuxSocket fd, boolean active) {
super(null, fd, active);
}
所有的建構函式都需要一個LinuxSocket的引數,LinuxSocket是一個socket用來提供對於linux native方法的訪問支援。
同樣的,我們再看一下AbstractKQueueServerChannel的建構函式:
AbstractKQueueServerChannel(BsdSocket fd) {
this(fd, isSoErrorZero(fd));
}
AbstractKQueueServerChannel(BsdSocket fd, boolean active) {
super(null, fd, active);
}
AbstractKQueueServerChannel的建構函式需要傳入一個BsdSocket引數,BsdSocket是一個類用來提供對BSD系統的本地方法的訪問。
AbstractServerChannel
AbstractServerChannel我們在之前的channel一章中已經講過了,它的唯一實現就是LocalServerChannel,用於本地的transport。
ServerSocketChannel
ServerSocketChannel是一個以Socket連線為基礎的ServerChannel,既然是Socket連線,那麼ServerSocketChannel中提供了一個InetSocketAddress型別的localAddress和一個remoteAddress, 另外還有一個ServerSocketChannelConfig屬性,用來儲存ServerSocketChannel相關的配置資訊:
public interface ServerSocketChannel extends ServerChannel {
@Override
ServerSocketChannelConfig config();
@Override
InetSocketAddress localAddress();
@Override
InetSocketAddress remoteAddress();
}
ServerDomainSocketChannel
ServerDomainSocketChannel是使用DomainSocket來進行通訊的ServerChannel。什麼是DomainSocket呢?
DomainSocket的全稱是unix domain socket,它又可以叫做IPC socket,也就是inter-process communication socket,是在unix平臺上的同一伺服器上的程式通訊方式。
我們知道,協議是比較複雜的,對於傳統的socket通訊來說,需要定製特定的協議,然後進行封包和解包等操作,但是使用DomainSocket,可以直接將程式的資料直接拷貝,從而節約了時間,並提高了程式的效率。
DomainSocket的地址是一個檔案的路徑,實際上是下面的一個結構體:
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX ,2位元組*/
char sun_path[UNIX_PATH_MAX]; /* 路徑名 */
};
在ServerDomainSocketChannel中的remoteAddress和localAddress的型別都是DomainSocketAddress,DomainSocketAddress有一個socketPath屬性,用來儲存DomainSocket檔案的路徑。
SctpServerChannel
最後一個要講解的ServerChannel是SctpServerChannel,Sctp的全稱是Stream Control Transmission Protocol,他是一種類似於TCP/IP的協議。和SocketServerChannel一樣,SctpServerChannel中也有一個config叫做SctpServerChannelConfig,還提供了多個bindAddress方法用來繫結InetAddress.
有關Sctp協議的具體內容,本章不深入討論,感興趣的朋友可以關注後續的章節。
Channel和它的型別
Channel作為ServerChannel的父類,又有哪些實現呢?
先來看下常用channel的實現類:
看起來channel的實現類非常多,基本上都是按照channel中使用傳輸協議的型別來的。
我們具體來看一下相應的實現類。
UnixChannel
UnixChannel表示的unix平臺上的操作,它有一個fd方法,返回一個FileDescriptor:
FileDescriptor fd();
這也是unix和windows平臺的區別之一,unix平臺所有的一切都可以用檔案來表示。
SctpChannel
在上面我講SctpServerChannel的時候我們提過了,Sctp是一個類似於tcp/ip的協議,SctpChannel中定義了協議中需要使用到的localAddress和remoteAddress:
InetSocketAddress localAddress();
InetSocketAddress remoteAddress();
同時還定義了一些繫結方法:
ChannelFuture bindAddress(InetAddress var1);
ChannelFuture bindAddress(InetAddress var1, ChannelPromise var2);
ChannelFuture unbindAddress(InetAddress var1);
ChannelFuture unbindAddress(InetAddress var1, ChannelPromise var2);
DatagramChannel
DatagramChannel用來處理UDP協議的連線,因為UDP有廣播的功能,所以DatagramChannel中提供了joinGroup的方法,來join一個multicast group:
ChannelFuture joinGroup(InetAddress multicastAddress);
當然,可以join就可以leave,還有一些leaveGroup的方法:
ChannelFuture leaveGroup(InetAddress multicastAddress);
還可以block某些地址在給定的networkInterface上的廣播:
ChannelFuture block(
InetAddress multicastAddress, NetworkInterface networkInterface,
InetAddress sourceToBlock);
這些方法都和UDP的特性是息息相關的。
DomainDatagramChannel
DomainDatagramChannel和之前提到的ServerDomainSocketChannel一樣,都是使用的IPC內部程式通訊技術,直接進行程式的拷貝,免去了協議解析等步驟,提升了處理速度。
DuplexChannel
DuplexChannel從名字看就是一個雙向的channel,duplex Channel有一個特點,就是channel的兩邊可以獨立的關閉,所以有下面的方法:
boolean isInputShutdown();
ChannelFuture shutdownInput();
boolean isOutputShutdown();
ChannelFuture shutdownOutput();
DuplexChannel的是實現有很多種,比如常見的NIOSocketChannel,KQueueSocketChannel,EpollSocketChannel等。
AbstractChannel
另外一個channel的非常重要的子類就是AbstractChannel,AbstractChannel有三個非常重要的實現,分別是AbstractNioChannel,AbstractKQueueChannel和AbstractEpollChannel。
這三個類使用的都是NIO技術,不同的是第一個使用的是select,後面兩個使用的是平臺獨有的KQueue和Epoll技術。
其中NIO又可以分為NioByteChannel和NioMessageChannel,KQueue和Epoll又可以分為StreamChannel和DatagramChannel。
總結
以上就是channel在netty中的基本實現和分類。後面我們會詳解講解具體的channel到底是如何實現的。
本文已收錄於 www.flydean.com
最通俗的解讀,最深刻的乾貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程式那些事」,懂技術,更懂你!