Netty详解(三):Netty 入门应用
1. Netty服务端开发
TimeServer.java
package com.basic.netty.bio;import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;public class TimeServer {public void bind(int port)throws Exception{//配置服务端的NIO线程组,包包含了一组NIO线程,专门用于网络事件的处理,//实际上它们就是Reactor线程组。//这里创建了两个,一个用于服务端接受客户端的连接,//另一个用于进行SocketChannel的网络读写。EventLoopGroup bossGroup = new NioEventLoopGroup();EventLoopGroup workerGroup=new NioEventLoopGroup();try{//Netty用于启动NIO服务端的辅助启动类,目的是降低服务端的开发复杂度ServerBootstrap b = new ServerBootstrap();//将两个NIO线程组当作入参传递到ServerBootstrap中b.group(bossGroup,workerGroup)//功能对应于JDK NIO类库中的ServerSocketChannel类.channel(NioServerSocketChannel.class)//配置TCP参数,这里将backlog设置为1024.option(ChannelOption.SO_BACKLOG,1024)//绑定I/O事件的处理类ChildChannelHandler,它//的作用类似于Reactor模式中的Handler类,主要用于处理网络I/O事件,例如记录日志、对消息进行编解码等。.childHandler(new ChildChannelHandler());//绑定端口,同步等待成功ChannelFuture f=b.bind(port).sync();//调用同步阻塞方法sync 等待绑定操作完成,完成后Netty会返回一个ChannelFuture,//它的功能类似于JDK 的 java.util.concurrent.Future,主要用于异步操作的通知回调。//等待服务端链路关闭之后main函数才退出。f.channel().closeFuture().sync();}finally{//优雅退出,翻放线程池资源bossGroup.shutdownGracefully();workerGroup.shutdownGracefully();}}private class ChildChannelHandler extends ChannelInitializer<SocketChannel>{@Overrideprotected void initChannel(SocketChannel arg0) throws Exception {arg0.pipeline().addLast(new TimeServerHandler());}}public static void main(String[] args) throws Exception{int port=8080;new TimeServer().bind(port);}
}
TimeServerHandler.java
package com.basic.netty.bio;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;//从ChannelHandlerAdapter继承,用于对网络事件进行读写操作,通常只需要关注channelRead和exceptionCaught方法
public class TimeServerHandler extends ChannelHandlerAdapter{//channelRead() 该方法在接受到数据的时候自动调用(会存在半包问题)@Overridepublic void channelRead(ChannelHandlerContext ctx,Object msg)throws Exception{//类型转换,将msg转换为Netty的ByteBuf,类似JDK的java.nio.ByteBuffer对象ByteBuf buf=(ByteBuf)msg;//获取缓冲区可读字节数,创建byte数组byte[] req=new byte[buf.readableBytes()];//将缓冲区字节复制到新建的数组中buf.readBytes(req);//获取请求消息String body=new String(req,"UTF-8");System.out.println("The time server receive order : "+body);String currentTime="QUERY TIME ORDER".equalsIgnoreCase(body)?new java.util.Date(System.currentTimeMillis()).toString():"BAD ORDER";ByteBuf resp =Unpooled.copiedBuffer(currentTime.getBytes());ctx.write(resp);}@Overridepublic void channelReadComplete(ChannelHandlerContext ctx)throws Exception{/*将消息发送队列中的消息写入到SocketChannel中发送给对方。从性能角度考虑,为了防止频繁地唤醒Selector进行消息发送,Netty的write方法并不直接将消息写入SocketChannel中,调用write方法只是把待发送的消息放到发送缓冲数组中,再通过调用flush方法,将发送的缓冲区的消息全部写到SocketChannel中*/ctx.flush();}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){//发生异常时,关闭ChannelHandlerContextctx.close();}
}
2. Netty客户端开发
TimeClient.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
public class TimeClient {public void connect(int port,String host) throws Exception{EventLoopGroup group=new NioEventLoopGroup();try{Bootstrap b=new Bootstrap();//Channel需要设置为NioSocketChannel,然后为其添加Handlerb.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true).handler(new ChannelInitializer<SocketChannel>(){//为了简单直接创建匿名内部类,实现initChannel方法//其作用是当创建NioSocketChannel成功之后,在进行初始化时,//将它的ChannelHandler设置到ChannelPipeline中,用于处理网络I/O事件@Overridepublic void initChannel(SocketChannel ch) throws Exception{ch.pipeline().addLast(new TimeClientHandler());}});//发起异步连接,然后调用同步方法等待连接成功ChannelFuture f=b.connect(host,port).sync();//当客户端连接关闭之后,客户端主函数退出,退出前释放NIO线程组的资源f.channel().closeFuture().sync();}finally{}}public static void main(String[] args) throws Exception {int port=8080;new TimeClient().connect(port, "127.0.0.1");}
}
TimeClientHandler.java
import java.util.logging.Logger;import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;public class TimeClientHandler extends ChannelHandlerAdapter{private static final Logger logger=Logger.getLogger(TimeClientHandler.class.getName());private final ByteBuf firstMessage;public TimeClientHandler(){byte[] req="QUERY TIME ORDER".getBytes();firstMessage=Unpooled.buffer(req.length);firstMessage.writeBytes(req);}/*** 当客户端和服务器TCP链路建立成功后,NIO线程会调用channelActive方法*/@Overridepublic void channelActive(ChannelHandlerContext ctx){//发送查询时间的指令给服务端ctx.writeAndFlush(firstMessage);}/*** 当服务端返回应答消息时调用*/@Overridepublic void channelRead(ChannelHandlerContext ctx,Object msg)throws Exception{ByteBuf buf=(ByteBuf)msg;byte[] req=new byte[buf.readableBytes()];buf.readBytes(req);String body=new String(req,"UTF-8");System.out.println("Now is : " + body);}/*** 当发生异常时*/@Overridepublic void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){logger.warning("Unexpected exception from downstrea : " + cause.getMessage());ctx.close();}
}
上述例程仍没有考虑读半包的处理,但进行性能或者压力测试将不能正确工作。
3. 总结
- 当channel上面有数据到来时会触发channelRead事件,当数据到来时,eventLoop被唤醒继而调用channelRead方法处理数据。
- 当Channel上一旦没有更多数据要从底层传输中读取,就会触发channelReadComplete()。可能是以下两种情况,read到0个字节或者是read到的字节数小于buffer的容量,满足以上条件就会调用channelReadComplete方法。
Netty详解(三):Netty 入门应用相关推荐
- Netty详解(持续更新中)
Netty详解 1. Netty概述 1.1 Netty简介 1.2 原生NIO问题 1.3 Netty特点 1.4 Netty应用场景 1.3 Netty版本说明 2. Java IO模型 2.1 ...
- 第43课: Spark 1.6 RPC内幕解密:运行机制、源码详解、Netty与Akka等
第43课: Spark 1.6 RPC内幕解密:运行机制.源码详解.Netty与Akka等 Spark 1.6推出了以RpcEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构 ...
- Android Studio 插件开发详解三:翻译插件实战
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78113868 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...
- Android Studio 插件开发详解一:入门练手
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112003 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...
- P2P技术详解(三):P2P技术之STUN、TURN、ICE详解
本文是<P2P理论详解>系列文章中的第2篇,总目录如下: <P2P技术详解(一):NAT详解--详细原理.P2P简介> <P2P技术详解(二):P2P中的NAT穿越(打洞 ...
- Python零基础速成班-第14讲-Python处理Excel和Word,使用openpyxl和docx包详解,图表入门
Python零基础速成班-第14讲-Python处理Excel和Word,使用openpyxl和docx包详解,图表入门 学习目标 Python处理Excel(使用openpyxl包).图表入门\ P ...
- java中batch基础_详解Spring batch 入门学习教程(附源码)
详解Spring batch 入门学习教程(附源码) 发布时间:2020-09-08 00:28:40 来源:脚本之家 阅读:99 作者:achuo Spring batch 是一个开源的批处理框架. ...
- python爬虫入门实例-Python爬虫天气预报实例详解(小白入门)
本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 要求是把你所在城市过去一年的历史数据爬出来. 分析网站 我们可以看到,我们需要的天气数据都是放在图表上的,在切换月份的时候,发现只有 ...
- python编程入门与案例详解pdf-Python爬虫天气预报实例详解(小白入门)
本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 这次要爬的站点是这个:http://www.weather.com.cn/forecast/ 要求是把你所在城市过去一年的历史数据爬 ...
- Android init.rc文件解析过程详解(三)
Android init.rc文件解析过程详解(三) 三.相关结构体 1.listnode listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了l ...
最新文章
- Eclipse假死,一直LoadingDescriptFor,找到原因了
- zigbee的路由器能分配网络地址吗_真核细胞无丝分裂能将核DNA精准的平均分配到两个子细胞中吗?...
- 易生信九天的转录组分析培训班总结
- CSS word-wrap强制换行截断长字符串
- nc文件服务器配置教程,nc文件服务器配置
- android 游戏摇杆ui,LayaBox实现2D游戏八方向虚拟摇杆
- java大佬用什么编辑器_大佬们都在用的几款简单易用的文本编辑器
- 【ACM】C++程序设计ACM题库总结
- JS函数传参长度限制
- 用三元运算符判断奇数和偶数
- 富有哲理的10则故事(必读经典)
- 经典算法51(来测测你的编程基础)
- MyBatis:万能Map和模糊查询(狂神)
- 利用swiper在vue中做轮播图,并改变轮播图的原有箭头、图片等内容
- Debian10自签CA证书
- CAD绘图设计中怎样删除CAD图层?怎样清理CAD图层文件?
- Android中MotionEvent的来源和ViewRootImpl
- 【项目】Vue3+TS 动态路由 面包屑 查询重置 列表
- 认识学习的重要性,拒绝摆烂
- 思科高级配置(配置标准ACL)