博客
关于我
Netty框架用法介绍&&RPC应用实践
阅读量:177 次
发布时间:2019-02-28

本文共 7400 字,大约阅读时间需要 24 分钟。

一、介绍Netty用法之前,先聊一下I/O:

       1)计算机中的信息交换机制
             网络I/O  、本地I/O  

       2)IO的演变历史:

             BIO、NIO、AIO  

       3)目前大家熟知的,哪些框架的底层通信在用Netty:

           Dubbo、RocketMQ、Spring、ElasticSearch、GRPC

           Spark、Hadoop、Flink

 

二、环境准备:

io.netty
netty-all
4.1.36.Final

三、demo示范,相关API参考代码注释

server代码:

public class MyServer {    public static void main(String[] args) throws Exception {        EventLoopGroup bossGroup = new NioEventLoopGroup();        EventLoopGroup wokerGroup = new NioEventLoopGroup();        //epoll Only supported on Linux        //EventLoopGroup bossGroup = new EpollEventLoopGroup();        //EventLoopGroup wokerGroup = new EpollEventLoopGroup();        try{            ServerBootstrap serverBootstrap = new ServerBootstrap();            //在服务器端的handler()方法表示对bossGroup起作用,而childHandler表示对wokerGroup起作用            serverBootstrap.group(bossGroup,wokerGroup) //绑定线程池                    .channel(NioServerSocketChannel.class) //指定使用的channel                    .childHandler(new MyServerInitializer())//绑定客户端连接时触发的操作                    .localAddress(8899) //绑定端口                    .option(ChannelOption.SO_BACKLOG,128)//配置主线程分配的最大线程数                    .childOption(ChannelOption.SO_KEEPALIVE,true);//保持长连接            ChannelFuture channelFuture = serverBootstrap.bind().sync();//服务器异步创建绑定            channelFuture.channel().closeFuture().sync();//关闭服务器通道        }finally {            bossGroup.shutdownGracefully();// 释放线程池资源            wokerGroup.shutdownGracefully();// 释放线程池资源        }    }}public class MyServerHandler extends SimpleChannelInboundHandler
{ @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { //打印出客户端地址 System.out.println(ctx.channel().remoteAddress()+", "+msg); //TODO 业务逻辑处理 query(msg) Student student = ServiceUtil.query(msg); //TODO 返回结果做编码处理 IJacksonSerializer serializer= new JacksonSerializer(); byte[] serialize = serializer.serialize(student); //TODO 处理结果返回给客户端 ctx.channel().writeAndFlush(serialize); } @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().localAddress().toString() + " 通道已激活!"); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { System.out.println(ctx.channel().localAddress().toString() + " 通道不活跃!"); super.channelInactive(ctx); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {//cause.printStackTrace(); System.out.println(ctx.channel().localAddress().toString() + " 连接断开或者异常!"); ctx.close(); }}public class MyServerInitializer extends ChannelInitializer
{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4)); pipeline.addLast(new LengthFieldPrepender(4)); //字符串解码 // pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); // //字符串编码 // pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8)); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));//字符串解码 pipeline.addLast(new ByteArrayEncoder());//字节数组编码 //自己定义的处理器 pipeline.addLast(new MyServerHandler());// 客户端触发操作 }}

Client代码:

public class MyClient {    public static void main(String[] args) throws Exception{        EventLoopGroup eventLoopGroup = new NioEventLoopGroup();        //epoll Only supported on Linux        //EventLoopGroup eventLoopGroup = new EpollEventLoopGroup();        try{            Bootstrap bootstrap = new Bootstrap();            bootstrap.group(eventLoopGroup)                    .channel(NioSocketChannel.class) // 使用NioSocketChannel来作为连接用的channel类                    .remoteAddress(new InetSocketAddress("localhost",8899)) // 绑定连接端口和host信息                    .handler(new MyClientInitializer());            ChannelFuture channelFuture = bootstrap.connect().sync();// 异步连接服务器            channelFuture.channel().closeFuture().sync();//异步等待关闭连接channel        }finally {            eventLoopGroup.shutdownGracefully().sync();// 释放线程池资源        }    }}public class MyClientHandler extends SimpleChannelInboundHandler {    @Override    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {//TODO 调用服务端,C可以是服务名称        ctx.writeAndFlush("C");//服务端的远程地址//System.out.println(ctx.channel().remoteAddress());        System.out.println("client output: "+msg.toString()+"time"+System.currentTimeMillis());//解码器,JacksonDecoder,已经将消息转成对象    }    /**     * 当服务器端与客户端进行建立连接的时候会触发,如果没有触发读写操作,则客户端和客户端之间不会进行数据通信,也就是channelRead0不会执行,     * 当通道连接的时候,触发channelActive方法向服务端发送数据触发服务器端的handler的channelRead0回调,然后     * 服务端向客户端发送数据触发客户端的channelRead0,依次触发。     */    @Override    public void channelActive(ChannelHandlerContext ctx) throws Exception {        ctx.writeAndFlush("客户端与服务端通道-关闭:"+ ctx.channel().localAddress() + "channelInactive");    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        cause.printStackTrace();        ctx.close();    }}public class MyClientInitializer extends ChannelInitializer
{ @Override protected void initChannel(SocketChannel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); pipeline.addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4)); pipeline.addLast(new LengthFieldPrepender(4)); // pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8));//字符串 // pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));//字符串 // pipeline.addLast(new ByteArrayDecoder());//字节码 // pipeline.addLast(new ByteArrayEncoder());//字节码 pipeline.addLast(new StringEncoder(CharsetUtil.UTF_8));//字符串 pipeline.addLast(new JacksonDecoder(Student.class));//Jackson pipeline.addLast(new MyClientHandler()); }}

四、Netty  RPC支持的编解码组件很多,也可以自定义扩展:

RPC通信编解码,Netty框架支持很多种:

自定义编解码:

public class JacksonDecoder extends MessageToMessageDecoder
{ private Class classtype; public JacksonDecoder(Class classtype) { this.classtype=classtype; } @Override protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List
list) throws Exception { byte[] array = new byte[byteBuf.readableBytes()]; byteBuf.getBytes(0, array); IJacksonSerializer serializer= new JacksonSerializer(); Object deserialize = serializer.deserialize(array, classtype); list.add(deserialize); }}public class JacksonEncoder extends MessageToMessageEncoder
{ public JacksonEncoder() { } @Override protected void encode(ChannelHandlerContext channelHandlerContext, byte[] bytes, List
list) throws Exception { //TODO 待实现 }}

 

五、ByteBuf介绍:

       Netty框架自带的组件,以下面的一段代码为例,这一块涉及零拷贝相关知识点,本处不做详细展开,后续单独详解。

byte[] array = new byte[byteBuf.readableBytes()];    byteBuf.getBytes(0, array);

六、线程池:

         NioEventLoopGroup   底层采用socket采用ServerSocketChannel,链接请求会注册到selector选择器:

EpollEventLoopGroup  只支持在Linux下使用,底层socket采用epoll,如果在windows下运行,服务的代码运行直接报“epoll Only supported on Linux” 错误:

        

        底层根据实际JDK的版本,如果是Linux,则会采用epoll模型。

     

     当前本地是WINDOWS: 

 

转载地址:http://kosn.baihongyu.com/

你可能感兴趣的文章
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_根据binlog实现数据实时delete同步_实际操作04---大数据之Nifi工作笔记0043
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置binlog_使用处理器抓取binlog数据_实际操作01---大数据之Nifi工作笔记0040
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_实现数据插入数据到目标数据库_实际操作03---大数据之Nifi工作笔记0042
查看>>
NIFI从MySql中增量同步数据_通过Mysql的binlog功能_实时同步mysql数据_配置数据路由_生成插入Sql语句_实际操作02---大数据之Nifi工作笔记0041
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_03_来吧用NIFI实现_数据分页获取功能---大数据之Nifi工作笔记0038
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_不带分页处理_01_QueryDatabaseTable获取数据_原0036---大数据之Nifi工作笔记0064
查看>>
NIFI从MySql中离线读取数据再导入到MySql中_无分页功能_02_转换数据_分割数据_提取JSON数据_替换拼接SQL_添加分页---大数据之Nifi工作笔记0037
查看>>
NIFI从PostGresql中离线读取数据再导入到MySql中_带有数据分页获取功能_不带分页不能用_NIFI资料太少了---大数据之Nifi工作笔记0039
查看>>
nifi使用过程-常见问题-以及入门总结---大数据之Nifi工作笔记0012
查看>>
NIFI分页获取Mysql数据_导入到Hbase中_并可通过phoenix客户端查询_含金量很高的一篇_搞了好久_实际操作05---大数据之Nifi工作笔记0045
查看>>
NIFI分页获取Postgresql数据到Hbase中_实际操作---大数据之Nifi工作笔记0049
查看>>
NIFI同步MySql数据_到SqlServer_错误_驱动程序无法通过使用安全套接字层(SSL)加密与SQL Server_Navicat连接SqlServer---大数据之Nifi工作笔记0047
查看>>
NIFI同步MySql数据源数据_到原始库hbase_同时对数据进行实时分析处理_同步到清洗库_实际操作06---大数据之Nifi工作笔记0046
查看>>
Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066
查看>>
NIFI大数据进阶_FlowFile拓扑_对FlowFile内容和属性的修改删除添加_介绍和描述_以及实际操作---大数据之Nifi工作笔记0023
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_处理器介绍_处理过程说明---大数据之Nifi工作笔记0019
查看>>
NIFI大数据进阶_FlowFile生成器_GenerateFlowFile处理器_ReplaceText处理器_实际操作---大数据之Nifi工作笔记0020
查看>>
NIFI大数据进阶_Json内容转换为Hive支持的文本格式_操作方法说明_01_EvaluteJsonPath处理器---大数据之Nifi工作笔记0031
查看>>
NIFI大数据进阶_Kafka使用相关说明_实际操作Kafka消费者处理器_来消费kafka数据---大数据之Nifi工作笔记0037
查看>>
NIFI大数据进阶_Kafka使用相关说明_实际操作Kafka生产者---大数据之Nifi工作笔记0036
查看>>