netty系列之:在netty中使用native传输协议
简介
对于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传输协议的使用,具体的代码,大家可以参考:
更多内容请参考 http://www.flydean.com/52-netty-native-transport-md/
最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!
欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!
netty系列之:在netty中使用native传输协议的更多相关文章
- netty系列之:请netty再爱UDT一次
		
目录 简介 netty对UDT的支持 搭建一个支持UDT的netty服务 异常来袭 TypeUDT和KindUDT 构建ChannelFactory SelectorProviderUDT 使用UDT ...
 - netty系列之: 在netty中使用 tls 协议请求 DNS 服务器
		
目录 简介 支持DoT的DNS服务器 搭建支持DoT的netty客户端 TLS的客户端请求 总结 简介 在前面的文章中我们讲过了如何在netty中构造客户端分别使用tcp和udp协议向DNS服务器请求 ...
 - netty系列之:在netty中使用protobuf协议
		
目录 简介 定义protobuf 定义handler 设置ChannelPipeline 构建client和server端并运行 总结 简介 netty中有很多适配不同协议的编码工具,对于流行的goo ...
 - netty系列之:在netty中处理CORS
		
目录 简介 服务端的CORS配置 CorsConfigBuilder CorsHandler netty对cors的支持 总结 简介 CORS的全称是跨域资源共享,他是一个基于HTTP-header检 ...
 - netty系列之:使用netty搭建websocket服务器
		
目录 简介 netty中的websocket websocket的版本 FrameDecoder和FrameEncoder WebSocketServerHandshaker WebSocketFra ...
 - netty系列之:使用netty搭建websocket客户端
		
目录 简介 浏览器客户端 netty对websocket客户端的支持 WebSocketClientHandshaker WebSocketClientCompressionHandler netty ...
 - netty系列之:使用netty实现支持http2的服务器
		
目录 简介 基本流程 CleartextHttp2ServerUpgradeHandler Http2ConnectionHandler 总结 简介 上一篇文章中,我们提到了如何在netty中配置TL ...
 - 游戏编程系列[2]--游戏编程中RPC与OpLog协议的结合--序
		
在系列[1]中,我们展示了RPC调用协议的定义以及演示,通过方法定义以及协议约定,进行了协议约定以及调用过程的约定.然而,实际上在游戏中,调用过程之后,需要传输相对多的数据给服务端. 常用场景,客户端 ...
 - 1. 彤哥说netty系列之开篇(有个问卷调查)
		
你好,我是彤哥,本篇是netty系列的第一篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 本文主要讲述netty系列的整体规划,并调查一下大家喜欢的学习方式. 知识点 ne ...
 
随机推荐
- 2021.08.16 P1260 工程规划(差分约束)
			
2021.08.16 P1260 工程规划(差分约束) 重点: 1.跑最短路是为了满足更多约束条件. P1260 工程规划 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题意: 造 ...
 - Java第十周作业
			
1.编写一个方法,实现冒泡排序(由小到大),并调用该方法 package gc; public class gc { /** * @param args */ public static void m ...
 - Python学习笔记: 用pprint更漂亮的打印数据
			
pprint是一个标准库,它提供了pprint()函数 ,用来打印复杂数据时更漂亮 >>> from pprint import pprint >>> data = ...
 - windows 安装 kalfka 并快速启动
			
1.安装Java 环境 https://www.java.com/zh_CN/ 直接下载安装即可 (如果之前有配置过java环境 可以先跳过此步骤,但是如果运行的时候报错就需要把之前的jdk环境变量删 ...
 - linux开机报警无法进入系统
			
一.开机无法进入系统提示如下 二.输入"journactl"命令查看红色的日志提示什么错误 三.问题分析: 这是由于swap告警,根据报错信息可以分析出是这两个device设备访问 ...
 - Bugku练习题---MISC---啊哒
			
Bugku练习题---MISC---啊哒 flag:flag{3XiF_iNf0rM@ti0n} 解题步骤: 1.观察题目,下载附件 2.下载以后发现是一张图片,从表面看没有什么有价值的信息 3.直接 ...
 - XCTF练习题---CRYPTO---不仅仅是Morse
			
XCTF练习题---CRYPTO---不仅仅是Morse flag:cyberpeace{attackanddefenceworldisinteresting} 解题步骤: 1.观察题目,下载附件 2 ...
 - Apollo的docker配置详解步骤
			
Apollo 的docker配置 基础环境 centOS7 + Docker服务 + mysql服务 1. 下载Apollo的包 git clone https://github.com/ctripc ...
 - GET 与 POST 其实没有什么区别
			
GET 与 POST 其实没有什么区别 本文写于 2020 年 12 月 30 日 GET 与 POST 是两种 HTTP 方法,并且是最常用的两种. 今天在使用 Postman 测试 api 的时候 ...
 - CSAPP 之 AttackLab 详解
			
前言 本篇博客将会介绍 CSAPP 之 AttackLab 的攻击过程,利用缓冲区溢出错误进行代码注入攻击和 ROP 攻击.实验提供了以下几个文件,其中 ctarget 可执行文件用来进行代码注入攻击 ...