简介

咱们晓得netty的根底是channel和在channel之上的selector,当然作为一个nio框架,channel和selector不仅仅是netty的根底,也是所有nio实现的根底。

同样的,咱们晓得netty很多种不同的协定,这些协定都是在channel上进行通信的,那么对于不同的协定来说,应用的channel和selector会有所不同吗?

带着这个疑难,咱们一起来深刻探索一下吧。

netty服务的根本构建形式

netty能够分为客户端和服务器端,实际上客户端和服务器端的结构形式差异不大,这里为了简略起见,以netty中服务器端的构建为例子进行钻研。

回顾一下咱们最开始搭建的netty服务器,其对应的代码如下:

 //建设两个EventloopGroup用来解决连贯和音讯        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup workerGroup = new NioEventLoopGroup();        try {            ServerBootstrap b = new ServerBootstrap();            b.group(bossGroup, workerGroup)                    .channel(NioServerSocketChannel.class)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        @Override                        public void initChannel(SocketChannel ch) throws Exception {                            ch.pipeline().addLast(new FirstServerHandler());                        }                    })                    .option(ChannelOption.SO_BACKLOG, 128)                    .childOption(ChannelOption.SO_KEEPALIVE, true);            // 绑定端口并开始接管连贯            ChannelFuture f = b.bind(port).sync();

咱们要留神的是两个中央,一个是ServerBootstrap的group办法,一个是它的channel办法。

EventLoopGroup

group有两种实现形式,能够带一个参数,也能够带两个参数。参数都是EventLoopGroup,EventLoopGroup次要用来注册channel, 供后续的Selector进行抉择。

如果应用一个参数的模式,则一个EventLoopGroup同时解决acceptor和client的事件,如果应用两个参数,则会将两者离开。

当然,这都不是明天要讲的重点,明天要讲的是EventLoopGroup的构建在不同的协定中有什么不同。

EventLoopGroup自身是一个接口,他有很多种实现,然而实质上还是两种EventLoop:SingleThreadEventLoop和MultithreadEventLoopGroup.

也就是用单线程进行EventLoop解决和多线程进行EventLoop解决。

比方下面咱们罕用的NioEventLoopGroup,就是一个单线程的EventLoop。

NioEventLoopGroup通常咱们应用的是无参的构造函数,实际上NioEventLoopGroup能够传入ThreadFactory,thread的个数,SelectorProvider和SelectStrategyFactory.

netty只提供了一个SelectStrategyFactory的实现:DefaultSelectStrategyFactory。

而对应SelectorProvider来说,默认的实现是SelectorProvider.provider(), 咱们看下这个办法的具体实现:

    public static SelectorProvider provider() {        synchronized (lock) {            if (provider != null)                return provider;            return AccessController.doPrivileged(                new PrivilegedAction<SelectorProvider>() {                    public SelectorProvider run() {                            if (loadProviderFromProperty())                                return provider;                            if (loadProviderAsService())                                return provider;                            provider = sun.nio.ch.DefaultSelectorProvider.create();                            return provider;                        }                    });        }    }

能够看到默认状况下,SelectorProvider有三种创立形式。

第一种就是从零碎属性中查找:java.nio.channels.spi.SelectorProvider:

String cn = System.getProperty("java.nio.channels.spi.SelectorProvider");Class<?> c = Class.forName(cn, true,                                       ClassLoader.getSystemClassLoader());            provider = (SelectorProvider)c.newInstance();

如果有定义,则创立一个实例返回。

如果没有的话,则会从"META-INF/services/"中加载service Loader :

    private static boolean loadProviderAsService() {        ServiceLoader<SelectorProvider> sl =            ServiceLoader.load(SelectorProvider.class,                               ClassLoader.getSystemClassLoader());        Iterator<SelectorProvider> i = sl.iterator();

如果servie也没有找到的话,则会应用最初默认的sun.nio.ch.DefaultSelectorProvider.

channel

默认状况下,咱们应用的是NioServerSocketChannel。他理论是从下面提到的默认的SelectorProvider来创立的。

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();return DEFAULT_SELECTOR_PROVIDER.openServerSocketChannel();

所以应用的channel须要跟selector相匹配。

咱们能够间接应用channel,也能够应用ChannelFactory,通过这些Factory来生成channel。

如果要应用ChannelFactory,则能够调用ServerBootstrap的channelFactory办法。

多种构建形式

下面提到了最根本的netty server构建形式。对应的是socket协定。

如果是要进行UDP连贯,对应的channel应该换成NioDatagramChannel,如下:

EventLoopGroup group = new NioEventLoopGroup();        try {            Bootstrap b = new Bootstrap();            b.group(group)             .channel(NioDatagramChannel.class)             .option(ChannelOption.SO_BROADCAST, true)             .handler(new UDPServerHandler());            b.bind(PORT).sync().channel().closeFuture().await();

EventLoopGroup能够放弃不变。

因为netty底层是基于Socket进行通信的,socket底层又是基于TCP或者UDP协定,所以在netty中实现的http或者http2或者SOCKS协定都是在socket连贯根底上进行的。

所以对http或者http2来说,channel还是NioServerSocketChannel。

能够看到只有UDP协定有所不同。同样的基于UDP协定之上的UDT协定也是不同的,其应用如下:

 final NioEventLoopGroup acceptGroup = new NioEventLoopGroup(1, acceptFactory, NioUdtProvider.BYTE_PROVIDER);        final NioEventLoopGroup connectGroup = new NioEventLoopGroup(1, connectFactory, NioUdtProvider.BYTE_PROVIDER); final ServerBootstrap boot = new ServerBootstrap();            boot.group(acceptGroup, connectGroup)                    .channelFactory(NioUdtProvider.BYTE_ACCEPTOR)                    .option(ChannelOption.SO_BACKLOG, 10)                    .handler(new LoggingHandler(LogLevel.INFO))                    .childHandler(new ChannelInitializer<UdtChannel>() {                        @Override                        public void initChannel(final UdtChannel ch) {                            ch.pipeline().addLast(                                    new LoggingHandler(LogLevel.INFO),                                    new UDTEchoServerHandler());                        }                    });

UDT应用的是NioUdtProvider中提供的BYTE_PROVIDER和BYTE_ACCEPTOR别离作为selector和channelFactory。

其余的channel

除了NioSocketChannel之外,还有EpollChannel、KQueueChannel、SctpChannel,这些channel都是针对不同协定来应用的。咱们会在后续的文章中具体进行介绍。

总结

channel和selector是netty的根底,在这根底之上,netty能够扩大适配所有基于tcp和udp的协定,能够说十分的弱小。

本文已收录于 http://www.flydean.com/39-netty-selecto…r-channelfactory/

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

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