简介

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*结尾的实现为例,上面是他们的继承关系:

<img src="https://img-blog.csdnimg.cn/9613bc4cb9314dc2903a938f80340b47.png" style="zoom:67%;" />

从上图咱们能够看出,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的实现类:

<img src="https://img-blog.csdnimg.cn/69d7d0d53df847e2b5eb7791da956ef1.png" style="zoom:67%;" />

看起来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

最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!

欢送关注我的公众号:「程序那些事」,懂技术,更懂你!