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 入门应用相关推荐

  1. Netty详解(持续更新中)

    Netty详解 1. Netty概述 1.1 Netty简介 1.2 原生NIO问题 1.3 Netty特点 1.4 Netty应用场景 1.3 Netty版本说明 2. Java IO模型 2.1 ...

  2. 第43课: Spark 1.6 RPC内幕解密:运行机制、源码详解、Netty与Akka等

    第43课: Spark 1.6 RPC内幕解密:运行机制.源码详解.Netty与Akka等 Spark 1.6推出了以RpcEnv.RPCEndpoint.RPCEndpointRef为核心的新型架构 ...

  3. Android Studio 插件开发详解三:翻译插件实战

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78113868 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  4. Android Studio 插件开发详解一:入门练手

    转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/78112003 本文出自[赵彦军的博客] 系列目录 Android Gradle使用 ...

  5. P2P技术详解(三):P2P技术之STUN、TURN、ICE详解

    本文是<P2P理论详解>系列文章中的第2篇,总目录如下: <P2P技术详解(一):NAT详解--详细原理.P2P简介> <P2P技术详解(二):P2P中的NAT穿越(打洞 ...

  6. Python零基础速成班-第14讲-Python处理Excel和Word,使用openpyxl和docx包详解,图表入门

    Python零基础速成班-第14讲-Python处理Excel和Word,使用openpyxl和docx包详解,图表入门 学习目标 Python处理Excel(使用openpyxl包).图表入门\ P ...

  7. java中batch基础_详解Spring batch 入门学习教程(附源码)

    详解Spring batch 入门学习教程(附源码) 发布时间:2020-09-08 00:28:40 来源:脚本之家 阅读:99 作者:achuo Spring batch 是一个开源的批处理框架. ...

  8. python爬虫入门实例-Python爬虫天气预报实例详解(小白入门)

    本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 要求是把你所在城市过去一年的历史数据爬出来. 分析网站 我们可以看到,我们需要的天气数据都是放在图表上的,在切换月份的时候,发现只有 ...

  9. python编程入门与案例详解pdf-Python爬虫天气预报实例详解(小白入门)

    本文研究的主要是Python爬虫天气预报的相关内容,具体介绍如下. 这次要爬的站点是这个:http://www.weather.com.cn/forecast/ 要求是把你所在城市过去一年的历史数据爬 ...

  10. Android init.rc文件解析过程详解(三)

    Android init.rc文件解析过程详解(三) 三.相关结构体 1.listnode listnode结构体用于建立双向链表,这种结构广泛用于kernel代码中, android源代码中定义了l ...

最新文章

  1. Eclipse假死,一直LoadingDescriptFor,找到原因了
  2. zigbee的路由器能分配网络地址吗_真核细胞无丝分裂能将核DNA精准的平均分配到两个子细胞中吗?...
  3. 易生信九天的转录组分析培训班总结
  4. CSS word-wrap强制换行截断长字符串
  5. nc文件服务器配置教程,nc文件服务器配置
  6. android 游戏摇杆ui,LayaBox实现2D游戏八方向虚拟摇杆
  7. java大佬用什么编辑器_大佬们都在用的几款简单易用的文本编辑器
  8. 【ACM】C++程序设计ACM题库总结
  9. JS函数传参长度限制
  10. 用三元运算符判断奇数和偶数
  11. 富有哲理的10则故事(必读经典)
  12. 经典算法51(来测测你的编程基础)
  13. MyBatis:万能Map和模糊查询(狂神)
  14. 利用swiper在vue中做轮播图,并改变轮播图的原有箭头、图片等内容
  15. Debian10自签CA证书
  16. CAD绘图设计中怎样删除CAD图层?怎样清理CAD图层文件?
  17. Android中MotionEvent的来源和ViewRootImpl
  18. 【项目】Vue3+TS 动态路由 面包屑 查询重置 列表
  19. 认识学习的重要性,拒绝摆烂
  20. 思科高级配置(配置标准ACL)

热门文章

  1. 想一下,最大公约数怎么求
  2. LeetCode Keyboard Row
  3. (转载)php array_merge 和 两数组相加区别
  4. .Net Remoting(应用程序域) - Part.1(转载)
  5. 工信部发布新能源车准入新规 9月1日起正式实施
  6. C++程序设计之可调用对象与标准库function
  7. 语音信号短时域分析之预处理(三)
  8. static 函数和普通函数
  9. 南信大计算机分类,南信大计算机原理样卷
  10. java中rpn_java – RPNCalculator代码混淆