乐趣区

关于java:netty系列之netty中各不同种类的channel详解

简介

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

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

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

退出移动版