简介
对于IO来说,除了传统的block IO,应用最多的就是NIO了,通常咱们在netty程序中最罕用到的就是NIO,比方NioEventLoopGroup,NioServerSocketChannel等。
咱们也晓得在IO中有比NIO更快的IO形式,比方kqueue和epoll,然而这两种形式须要native办法的反对,也就是说须要在操作系统层面提供服务。
如果咱们在反对Kqueue或者epoll的服务器上,netty是否能够提供对这些优良IO的反对呢?
答案是必定的。然而首先kqueue和epoll须要JNI反对,也就是说JAVA程序须要调用本地的native办法。
native传输协定的依赖
要想应用kequeue和epoll这种native的传输方式,咱们须要额定增加我的项目的依赖,如果是linux环境,则能够增加如下的maven依赖环境:
<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-epoll</artifactId> <version>${project.version}</version> <classifier>linux-x86_64</classifier> </dependency> ... </dependencies>
其中version须要匹配你所应用的netty版本号,否则可能呈现调用异样的状况。
classifier示意的是零碎架构,它的值能够是linux-x86_64,也能够是linux-aarch_64.
如果你应用的mac零碎,那么能够这样引入:
<dependencies> <dependency> <groupId>io.netty</groupId> <artifactId>netty-transport-native-kqueue</artifactId> <version>${project.version}</version> <classifier>osx-x86_64</classifier> </dependency> ... </dependencies>
netty除了独自的个体包之外,还有一个all in one的netty-all包,如果你应用了这个all in one的包,那么不须要额定增加native的依赖。
如果netty提供的零碎架构并没有你正在应用的,那么你须要手动进行编译,以下是编译所依赖的程序包, 如果是在RHEL/CentOS/Fedora零碎中,则应用:
sudo yum install autoconf automake libtool make tar \ glibc-devel \ libgcc.i686 glibc-devel.i686
如果是在Debian/Ubuntu零碎中,则应用:
sudo apt-get install autoconf automake libtool make tar \ gcc
如果是在MacOS/BSD零碎中,则应用:
brew install autoconf automake libtool
netty本地传输协定的应用
装置好依赖包之后,咱们就能够在netty中应用这些native传输协定了。
native传输协定的应用和NIO的应用基本一致,咱们只须要进行上面的替换即可。
如果是在liunx零碎中,则进行上面的替换:
NioEventLoopGroup → EpollEventLoopGroup NioEventLoop → EpollEventLoop NioServerSocketChannel → EpollServerSocketChannel NioSocketChannel → EpollSocketChannel
如果是在mac零碎中,则进行上面的替换:
NioEventLoopGroup → KQueueEventLoopGroup NioEventLoop → KQueueEventLoop NioServerSocketChannel → KQueueServerSocketChannel NioSocketChannel → KQueueSocketChannel
这里还是应用咱们相熟的聊天服务为例,首先看下基于Kqueue的netty服务器端应该怎么写:
EventLoopGroup bossGroup = new KQueueEventLoopGroup(1); EventLoopGroup workerGroup = new KQueueEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(KQueueServerSocketChannel.class) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new NativeChatServerInitializer()); Channel channel = b.bind(PORT).sync().channel(); log.info("server channel:{}", channel); channel.closeFuture().sync();
和NIO一样,在服务器端咱们须要应用KQueueEventLoopGroup创立两个EventLoopGroup,一个是bossGroup, 一个是workerGroup。
而后将这两个group传入到ServerBootstrap中,并且增加KQueueServerSocketChannel作为channel。
其余的内容和NIO server的内容是一样的。
接下来咱们看下基于Kqueue的netty客户端改如何跟server端建设连贯:
EventLoopGroup group = new KQueueEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group) .channel(KQueueSocketChannel.class) .handler(new NativeChatClientInitializer()); // 建设连贯 Channel ch = b.connect(HOST, PORT).sync().channel(); log.info("client channel: {}", ch);
这里应用的是KQueueEventLoopGroup,并将KQueueEventLoopGroup放到Bootstrap中,并且为Bootstrap提供了和server端统一的KQueueSocketChannel。
而后就是客户端向channel中写音讯,这里咱们间接从命令行输出:
// 从命令行输出 ChannelFuture lastWriteFuture = null; BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); for (;;) { String line = in.readLine(); if (line == null) { break; } // 将从命令行输出的一行字符写到channel中 lastWriteFuture = ch.writeAndFlush(line + "\r\n"); // 如果输出'再见',则期待server端敞开channel if ("再见".equalsIgnoreCase(line)) { ch.closeFuture().sync(); break; } }
下面代码的意思是将命令行收到的音讯写入到channel中,如果输出的是'再见',则敞开channel。
为了可能解决字符串,这里用到了三个编码解码器:
// 增加行分割器 pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter())); // 增加String Decoder和String Encoder,用来进行字符串的转换 pipeline.addLast(new StringEncoder()); pipeline.addLast(new StringDecoder());
别离是行分割器,字符编码器和字符解码器。
运行一下看,程序运行没问题,客户端和服务器端能够进行通信。
总结
这里咱们只以Kqueue为例介绍了netty中native传输协定的应用,具体的代码,大家能够参考:
learn-netty4
更多内容请参考 http://www.flydean.com/52-netty-native-transport-md/
最艰深的解读,最粗浅的干货,最简洁的教程,泛滥你不晓得的小技巧等你来发现!
欢送关注我的公众号:「程序那些事」,懂技术,更懂你!