【Netty】Netty之Bootstrapping
一、前言
前面已经学习了Netty的EventLoop以及线程模型,接着学习Netty的Bootstrapping。
二、Bootstrapping
在学习了Netty中的很多组件后,如何将这些组件有效的组合至应用程序中,这需要使用应用引导程序,引导应用程序是将其配置为运行的过程,Netty以一种绝对应用程序的方式处理引导。
2.1 Bootstrap类
Bootstrap类的继承结构图如下图所示。
一个服务器使用一个父通道来接受来自客户端的连接并创建子通道来与它们进行通信,而一个客户端很可能只需要一个非父通道来进行所有的网络交互,而前面讨论的组件会参与引导过程,有些在客户端和服务端都会被使用。两个应用程序类型共同的引导步骤由AbstractBootstrap处理,而特定于客户端或服务器的引导步骤分别由Bootstrap或ServerBootstrap处理。
为何Bootstrap为Cloneable?因为有时需要创建具有类似或相同设置的多个通道,为了支持此模式,不需要为每个通道创建和配置新的引导实例,因此将AbstractBootstrap标记为Cloneable,在已配置的引导程序上调用clone()方法将返回可立即使用的另一个引导实例,这只会创建引导程序的EventLoopGroup的浅层副本,所以其被所有克隆的通道共享。
2.2 引导客户端和无连接协议
Bootstrap在客户端或无连接协议的应用程序中使用。
1. 引导客户端
Bootstrap类负责为客户端和使用无连接协议的应用程序创建通道,如下图所示。
以下代码引导使用NIO TCP传输的客户端。
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioSocketChannel.class).handler(new SimpleChannelInboundHandler<ByteBuf>() {@Overrideprotected void channeRead0(ChannelHandlerContext channelHandlerContext,ByteBuf byteBuf) throws Exception {System.out.println("Received data");}} );ChannelFuture future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80)); future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture)throws Exception {if (channelFuture.isSuccess()) {System.out.println("Connection established");} else {System.err.println("Connection attempt failed");channelFuture.cause().printStackTrace();}} } );
2. Channel和EventLoopGroup兼容性
io.netty.channel包中的类结构如下。
可以看到对于NIO和OIO传输,都有相关的EventLoopGroup和Channel实现,不能混合具有不同前缀的组件,例如NioEventLoopGroup和OioSocketChannel。如下代码展示不兼容的使用用法。
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(OioSocketChannel.class).handler(new SimpleChannelInboundHandler<ByteBuf>() {@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext,ByteBuf byteBuf) throws Exception {System.out.println("Received data");}} ); ChannelFuture future = bootstrap.connect(new InetSocketAddress("www.manning.com", 80)); future.syncUninterruptibly();
其中NIOEventLooop和OioSocketChannel不兼容,将会抛出IllegalStateException异常。
在调用bind或者connect方法之前,需要调用group、channel或channelFactory、handler方法,否则会抛出IllegalStateException异常。
2.3 引导服务器
ServerChannel的实现负责创建接受连接的子通道,ServerBootstrap通过bind()方法创建一个ServerChannel,ServerChannel可管理多个子通道,具体如下图所示。
下面代码展示了如何引导服务器。
NioEventLoopGroup group = new NioEventLoopGroup(); ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(group).channel(NioServerSocketChannel.class).childHandler(new SimpleChannelInboundHandler<ByteBuf>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx,ByteBuf byteBuf) throws Exception {System.out.println("Received data");}} ); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture)throws Exception {if (channelFuture.isSuccess()) {System.out.println("Server bound");} else {System.err.println("Bound attempt failed");channelFuture.cause().printStackTrace();}} } );
2.4 由通道引导客户端
假设服务器正在处理客户端请求,并要求服务器作为第三个系统的客户端,如代理服务器。此时需要从ServerChannel引导客户端通道。一个较好的方法是通过Bootstrap类的group方法传递Channel对应的EventLoop,因为所有分配给EventLoop的通道都使用相同的线程,这避免了额外的线程创建和相关的上下文切换。具体如下图所示。
通过group方法共享EventLoop的代码如下。
ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class).childHandler(new SimpleChannelInboundHandler<ByteBuf>() {ChannelFuture connectFuture;@Overridepublic void channelActive(ChannelHandlerContext ctx)throws Exception {Bootstrap bootstrap = new Bootstrap();bootstrap.channel(NioSocketChannel.class).handler(new SimpleChannelInboundHandler<ByteBuf>() {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf in)throws Exception {System.out.println("Received data");}} );bootstrap.group(ctx.channel().eventLoop());connectFuture = bootstrap.connect(new InetSocketAddress("www.manning.com", 80));}@Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext,ByteBuf byteBuf) throws Exception {if (connectFuture.isDone()) {// do something with the data }}} );ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture)throws Exception {if (channelFuture.isSuccess()) {System.out.println("Server bound");} else {System.err.println("Bind attempt failed");channelFuture.cause().printStackTrace();}} } );
2.5 在引导过程中添加多个ChannelHandler
在上面示例中,在引导过程中通过调用handler或者childHandler方法添加单个ChannelHandler,并且我们知道在ChannelPipeline中可以有多个ChannelHandler链,但是在引导过程中只添加了一个ChannelHandler。Netty提供了ChannelInboundHandlerAdapter,其提供了initChannel方法,该方法可以将多个ChannelHandler添加至ChannelPipeline中,你只需要将ChannelInitializer的实现提供给引导程序,而一旦Channel注册了EventLoop,那么initChannel方法将被调用,当方法返回后,ChannelInitializer将自身从ChannelPipeline中移除,如下代码展示了具体的操作。
ServerBootstrap bootstrap = new ServerBootstrap(); bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializerImpl()); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); future.sync();final class ChannelInitializerImpl extends ChannelInitializer<Channel> {@Overrideprotected void initChannel(Channel ch) throws Exception {ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new HttpClientCodec());pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE));} }
2.6 使用Netty的ChannelOptions和attributes
当创建通道时手动配置非常麻烦,可以使用option方法将ChannelOptions提供给引导程序,你提供的值将自动应用于在引导中创建的所有通道。ChannelOptions包括连接详细信息,如保持活动、超时属性和缓冲区设置等。Netty还可使用AttributeKey抽象类来配置属性值,如下代码展示了具体使用。
final AttributeKey<Integer> id = new AttributeKey<Integer>("ID"); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new NioEventLoopGroup()) .channel(NioSocketChannel.class) .handler(new SimpleChannelInboundHandler<ByteBuf>() {@Overridepublic void channelRegistered(ChannelHandlerContext ctx)throws Exception {Integer idValue = ctx.channel().attr(id).get();// do something with the idValue @Overrideprotected void channelRead0(ChannelHandlerContext channelHandlerContext,ByteBuf byteBuf) throws Exception {System.out.println("Received data");}} ); bootstrap.option(ChannelOption.SO_KEEPALIVE,true).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); bootstrap.attr(id, 123456); ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); future.syncUninterruptibly();
2.7 引导DatagramChannels
前面的示例使用的SocketChannel,是基于TCP协议,但是Bootstrap也可以用于无连接的协议,如UDP协议,唯一的区别在于不调用connect方法,只使用bind方法,具体如下代码所示。
Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new OioEventLoopGroup()).channel(OioDatagramChannel.class).handler(new SimpleChannelInboundHandler<DatagramPacket>(){@Overridepublic void channelRead0(ChannelHandlerContext ctx,DatagramPacket msg) throws Exception {// Do something with the packet }} ); ChannelFuture future = bootstrap.bind(new InetSocketAddress(0)); future.addListener(new ChannelFutureListener() {@Overridepublic void operationComplete(ChannelFuture channelFuture)throws Exception {if (channelFuture.isSuccess()) {System.out.println("Channel bound");} else {System.err.println("Bind attempt failed");channelFuture.cause().printStackTrace();}} })
2.8 关闭
引导使得应用运行,但是之后需要优雅的关闭引导。需要关闭EventLoopGroup,可调用EventLoopGroup.shutdownGracefully() 方法,其是异步的,会返回ChannelFuture,在观泉关闭后会收到通知,下面是使用示例。
EventLoopGroup group = new NioEventLoopGroup(); Bootstrap bootstrap = new Bootstrap(); bootstrap.group(group).channel(NioSocketChannel.class); ... Future<?> future = group.shutdownGracefully(); // block until the group has shutdown future.syncUninterruptibly();
也可以在调用shutdownGracefully方法之前显示调用close方法,要让EventLoopGroup自己主动关闭。
三、总结
本篇博文讲解了Bootstrap,包括客户端和服务端的引导,以及如何启动标准的客户端和服务端程序。也谢谢各位园友的观看~
【Netty】Netty之Bootstrapping相关推荐
- Netty : netty 4如何解决空轮询bug
1.美图 2.概述 空轮询bug参考:Netty : 臭名昭出的JDK的NIO bug(空轮询bug) 4.netty4 解决 4.1 构建阈值 int selectorAutoRebuildThre ...
- Netty : netty 3如何解决空轮询bug
1.美图 2.概述 空轮询bug参考:Netty : 臭名昭出的JDK的NIO bug(空轮询bug) 3. netty 3 如何解决 netty3采用的是第三种方案,检测重点是select函数是否返 ...
- Netty -Netty心跳检测机制案例,Netty通过WebSocket编程实现服务器和客户端长链接
Netty心跳检测机制案例 案例要求 编写一个Netty心跳检测机制案例,当服务器超过3秒没有读时,就提示读空闲 当服务器超过5秒没有写操作时,提示写空闲 服务器超过7秒没有读或者写操作时,就提示读写 ...
- Netty —— Netty 模型
前文 NIO介绍 NIO -- 三大组件 Netty -- 概述 Netty -- 下载.安装 Reactor 模式(单 Reactor 单线程.单 Reactor 多线程.主从 Reactor 多线 ...
- dotnetty java netty,Netty(DotNetty)原理解析
一.背景介绍 DotNetty是微软的Azure团队,使用C#实现的Netty的版本发布.不但使用了C#和.Net平台的技术特点,并且保留了Netty原来绝大部分的编程接口.让我们在使用时,完全可以依 ...
- java 伪异步 netty,Netty(一) - 不死的达芬奇的个人空间 - OSCHINA - 中文开源技术交流社区...
一.我们先来看BIO的问题: 1 没有数据缓冲区,I/O性能存在问题: 2 没有C或C++中的Channel概念,只有输入和输出流: 3 通常会导致通信线程被长时间阻塞: 4 支持的字符集有限 ...
- 工作10年从大公司离职去小公司当CTO,被同事鄙视竟然不回netty
Netty easy of use! 面试官 不不不,咱得跟我聊聊BIO.NIO.SELECT.EPOLL Netty quick and easy development of network ap ...
- 【Netty】从 BIO、NIO 聊到 Netty
为了让你更好地了解 Netty 以及它诞生的原因,先从传统的网络编程说起吧! 还是要从 BIO 说起 传统的阻塞式通信流程 早期的 Java 网络相关的 API(java.net包) 使用 Socke ...
- Netty深入浅出(一)入门
传统Socket中,NIO和IO的比较(Nio知识回顾) IO 阻塞点: server.accept(); 和 单线程情况下只能有一个客户端 用线程池可以有多个客户端连接,但是非常消耗性能 NIO s ...
- netty源码分析系列——EventLoop
2019独角兽企业重金招聘Python工程师标准>>> 前言 EventLoop也是netty作为一个事件驱动架构的网络框架的重要组成部分,netty主要通过它来实现异步编程,从前面 ...
最新文章
- 设置VSCode刷新资源管理器快捷键Ctrl+Shift+R
- python生成表格文件_python 读取excel文件生成sql文件实例详解
- 含有无关项的序列检测
- XNA游戏:Hello XNA
- Android 第十二课 使用LitePal操作数据库(记得阅读最后面的注意事项哦)
- MyBatis入门(二)---一对一,一对多
- html背景图片只显示一张图片,img只显示图片一部分 或 css设置背景图片只显示图片指定区域(示例代码)...
- php程序阻塞与非阻塞的区别,完美起航
- as工程放到源码编译_「Do.016」AndroidStudio不用编译,阅读Android源码
- 安装win32com
- 每天一点matlab——字符分割
- VGA信号一些分辨率的参数(摘抄)
- 加快二代支付系统建设
- php无限评论回复_php实现无限级评论功能
- 2010-05-20 代码复用、使用率情况分析
- 多媒体计算机主要有哪些基本特性,多媒体计算机的基本特性
- MyBatis9.28 + jdk1.8+Mysql 5.7
- bzoj 3007 拯救小云公主
- arcgis测量面积长度
- Fiddler模拟发送POST请求
热门文章
- Powershell基本命令总结(更新中)
- Eclipse 快捷键 查看方法在那里被调用~
- 如何解决”ArcGIS Server Site is currently being configured by another administrative operation“的问题
- linux ifcfg-33 没有eth0解决方法
- Web方式预览Office/Word/Excel/pdf文件解决方案
- 如何检查python模块的版本?
- QTimer定时器的使用,判断ros是否关闭,ros关闭后关闭窗口
- Window+Java环境证书生成说明,pfx证书已经生成
- Linux与Windows之间实现文件实时同步的方案
- XElement.Load 需要释放吗_因为信用卡逾期还不上坐牢了,刑满释放后,还需要继续还钱吗?...