介绍我们知道netty的基础是通道和通道上的选择器。当然,作为一个nio框架,channel和selector不仅是netty的基础,也是所有nio实现的基础。同样,我们知道netty有很多不同的协议,这些协议在通道上进行通信。那么对于不同的协议,使用的channel和selector会不会不同呢?带着这个问题,让我们深入探讨一下。netty服务netty的基本构建方式分为客户端和服务端。其实在client和server的构建上并没有太大区别。这里为了简单起见,以netty中服务器的搭建为例进行研究。回顾一下我们一开始搭建的nettyserver,对应的代码如下://创建两个EventloopGroup,分别处理连接和消息EventLoopGroupbossGroup=newNioEventLoopGroup();EventLoopGroupworkerGroup=newNioEventLoopGroup();尝试{ServerBootstrapb=newServerBootstrap();b.group(bossGroup,workerGroup).channel(NioServerSocketChannel.class).childHandler(newChannelInitializer(){@OverridepublicvoidinitChannel(SocketChannelch)抛出异常{ch.pipeline().addLast(newFirstServerHandler());}}).option(ChannelOption.SO_BACKLOG,128).childOption(ChannelOption.SO_KEEPALIVE,true);//绑定端口并开始接收连接ChannelFuturef=b.bind(port).sync();我们要注意两个地方,一个是ServerBootstrap的group方法,一个是它的channel方法。EventLoopGroup组有两种实现方法,可以带一个参数,也可以带两个参数。参数都是EventLoopGroup,EventLoopGroup主要用来注册channel,供后续Selector选择。如果使用一个参数,一个EventLoopGroup会同时处理acceptor和client事件,如果使用两个参数,则两者会分开。当然,这不是今天要讲的重点。今天讲的是不同协议中EventLoopGroup的构建差异。EventLoopGroup本身是一个接口,它有很多实现,但本质上有两种EventLoop:SingleThreadEventLoop和MultithreadEventLoopGroup。即单线程EventLoop处理和多线程EventLoop处理。比如上面我们常用的NioEventLoopGroup就是一个单线程的EventLoop。NioEventLoopGroup通常使用无参构造函数。其实NioEventLoopGroup可以传入ThreadFactory和线程数。SelectorProvider和SelectStrategyFactory.netty只提供了SelectStrategyFactory的一个实现:DefaultSelectStrategyFactory。对于SelectorProvider,默认实现是SelectorProvider.provider(),我们看一下这个方法的具体实现:返回访问控制器。doPrivileged(newPrivilegedAction(){publicSelectorProviderrun(){if(loadProviderFromProperty())返回提供者;如果(loadProviderAsService())返回提供者;provider=sun.nio.ch.DefaultSelectorProvider.create();返回提供者;}});可以看到默认情况下,SelectorProvider有三种创建方法。首先是从系统属性中查找:java.nio.channels.spi.SelectorProvider:Stringcn=System.getProperty("java.nio.channels.spi.SelectorProvider");Class>c=Class.forName(cn,true,ClassLoader.getSystemClassLoader());provider=(SelectorProvider)c.newInstance();如果有定义,则创建一个实例并返回。如果没有,服务加载器将从“META-INF/services/”加载:Iteratori=sl.iterator();如果找不到服务,将使用最后一个默认的sun.nio.ch.DefaultSelectorProvider.channel。默认情况下,我们使用NioServerSocketChannel。他实际上是从上面提到的默认SelectorProvider创建的。privatestaticfinalSelectorProviderDEFAULT_SELECTOR_PROVIDER=SelectorProvider.provider();返回DEFAULT_SELECTOR_PROVIDER.openServerSocketChannel();所以使用的通道需要匹配选择器。我们可以直接使用通道,也可以使用ChannelFactory通过这些工厂来生成通道。如果要使用ChannelFactory,可以调用ServerBootstrap的channelFactory方法。多种搭建方式上面说了最基本的nettyserver搭建方式。对应socket协议。如果要建立UDP连接,对应的channel要换成NioDatagramChannel,如下:EventLoopGroupgroup=newNioEventLoopGroup();试试{Bootstrapb=newBootstrap();b.group(group).channel(NioDatagramChannel.class).option(ChannelOption.SO_BROADCAST,true).handler(newUDPServerHandler());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协议也有所区别,其用法如下:finalNioEventLoopGroupacceptGroup=newNioEventLoopGroup(1,acceptFactory,NioUdtProvider.BYTE_PROVIDER);finalNioEventLoopGroupconnectGroup=newNioEventLoopGroup(1,connectFactory,NioUdtProvider.BYTE;VIDER.BYTE)finalServerBootstrapboot=newServerBootstrap();boot.group(acceptGroup,connectGroup).channelFactory(NioUdtProvider.BYTE_ACCEPTOR).option(ChannelOption.SO_BACKLOG,10).handler(newLoggingHandler(LogLevel.INFO)).childHandler(newChannelUdtChannel>(){@OverridepublicvoidinitChannel(finalUdtChannelch){ch.pipeline().addLast(newLoggingHandler(LogLevel.INFO),newUDTEchoServerHandler());}});UDT使NioUdtProvider中提供的BYTE_PROVIDER和BYTE_ACCEPTOR分别作为selector和channelFactory。除了NioSocketChannel,其他通道还有EpollChannel、KQueueChannel、SctpChannel。这些通道用于不同的协议。我们将在后续文章中详细介绍。总结一下,channel和selector是netty的基础。在此基础上netty可以扩展适配所有基于tcp和udp的协议,可以说是非常强大了。本文已收录于http://www.flydean.com/39-netty-selecto…r-channelfactory/最流行的解读,最深刻的干货,最简洁的教程,很多你不知道的小技巧等你来发现!欢迎关注我的公众号:《程序那些事儿》,懂技术,更懂你!