Netty提供了应用启动的配置跟启动API,服务端:ServerBootstarp,客户端Bootstarp。
他们用来指定
EventLoopGroup
Channel
ChannelOptions
当Channel注册时,调用ChannelHandler
设置Attributes到指定Chanel。
绑定IP跟端口
ServerBootstarp绑定端口使用bind()。Bootstarp连接使用connect()。
关系:
客户端Bootstarp提供了以下方法:
group(..) : 设置EventLoopGroup,用于服务Channel中I/O操作
channel(..) 、channelFacotry(..) : 指定使用Channel。 NIO/OIO...
localAddress(...) :设置本地地址,端口
option(...) : 设置Channel的配置
attr(..) : 设置Channel的附加属性
handler(..) : 设置定义的ChannelHandler到ChannelPipeline中
clone() : 拷贝。
remoteAddress() : 设置远程连接地址,端口
connect() : 连接远程服务
bind() : 绑定本地服务
Bootstarp,bind()创建Channel后,调用connect(),将会建立连接与Channel()绑定。
若直接调用,则创建Channel 与建立的连接绑定。
Bootstrap bootstrap = new Bootstrap(); #1 bootstrap.group(new NioEventLoopGroup()) #2 .channel(NioSocketChannel.class) #3 .handler(new SimpleChannelInboundHandler<ByteBuf>() { #4 @Override protected void channeRead0( ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { System.out.println("Reveived data"); byteBuf.clear(); } }); ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); #5 future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { System.out.println("Connection established"); } else { System.err.println("Connection attempt failed"); channelFuture.cause().printStackTrace(); } } });
注意:使用NioSocketChannel,则要与NioEventLoopGourp结对绑定,否则报错,OIO同理。
服务端ServerBootstrap
group(..) : 设置EventLoopGroup,用于服务ServerChannel的I/O操作与接收Channels
channel(..)、channelFacotry : 设置ServerChannel
localAddress(...) : 设置ServerChannel绑定地址与端口
option(...) : 设置ServerChannel的配置
childOption(...) : 设置ServerChannel accept 并创建的 Channel的配置
attr(...) : 设置ServerChannel的额外属性
childAttr(...) : 设置ServerChannel accept 并创建的 Channel的额外属性
handler(...) : ServerChannel的ChannelHandler,有默认实现,无特别需求不指定
childHandler(...) : 设置由ServerChanel accpet到创建的Chanel的ChannelHandler,每个ChannelHandler 对应的处理不同客户端I/O
clone() : 拷贝
bind(...) : 绑定并启动服务。返回ChannelFutrue。
ServerBootstrap bootstrap = new ServerBootstrap(); #1 bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) #2 .channel(NioServerSocketChannel.class) #3 .childHandler(new SimpleChannelInboundHandler<ByteBuf>() { #4 @Override protected void channelRead0(ChannelHandlerContext ctx, ByteBuf byteBuf) throws Exception { System.out.println("Reveived data"); byteBuf.clear(); } }); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); #5 future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { System.out.println("Server bound"); } else { System.err.println("Bound attempt failed"); channelFuture.cause().printStackTrace(); } } });ServerBootstarp内嵌Bootstarp连接,共同EventLoop例子,使用场景,做代理,或服务端需要连接其他服务来获取数据处理。
ServerBootstrap bootstrap = new ServerBootstrap(); #1 bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) #2 .channel(NioServerSocketChannel.class) #3 .childHandler(new SimpleChannelInboundHandler<ByteBuf>() { #4 ChannelFuture connectFuture; @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { Bootstrap bootstrap = new Bootstrap(); #5 bootstrap.channel(NioSocketChannel.class) #6 .handler( new SimpleChannelInboundHandler<ByteBuf>() { #7 @Override protected void channelRead0( ChannelHandlerContext ctx, ByteBuf in) throws Exception { System.out.println("Reveived data"); in.clear(); } }); bootstrap.group(ctx.channel().eventLoop()); #8 connectFuture = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); #9 } @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { if (connectFuture.isDone()) { // do something with the data #10 } } }); ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); #11 future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { System.out.println("Server bound"); } else { System.err.println("Bound attempt failed"); channelFuture.cause().printStackTrace(); } } });ServerBootstarp 需要支持多种协议。我们需要加入多个ChannelHandler时候,使用继承ChannelInitializer,并实现initChannel方法,便可以把 Channel加入到ChanelPipeline中,并且与EventLoopGroup关联。例子:
ServerBootstrap bootstrap = new ServerBootstrap(); #1 bootstrap.group(new NioEventLoopGroup(), new NioEventLoopGroup()) #2 .channel(NioServerSocketChannel.class) #3 .childHandler(new ChannelInitializerImpl()); #4 ChannelFuture future = bootstrap.bind(new InetSocketAddress(8080)); #5 future.sync(); final class ChannelInitializerImpl extends ChannelInitializer<Channel> {#6 @Override protected void initChannel(Channel ch) throws Exception { ChannelPipeline pipeline = ch.pipeline(); #7 pipeline.addLast(new HttpClientCodec()); pipeline.addLast(new HttpObjectAggregator(Integer.MAX_VALUE)); } }ChannelOptions and attributes
channelOptions 可以设置 Channel的连接超时,keep-alive等
attributes 可以设置一些用户自定义的值。
final AttributeKey<Integer> id = new AttributeKey<Integer>("ID"); #1 Bootstrap bootstrap = new Bootstrap(); #2 bootstrap.group(new NioEventLoopGroup()) #3 .channel(NioSocketChannel.class) #4 .handler(new SimpleChannelInboundHandler<ByteBuf>() #5 @Override public void channelRegistered(ChannelHandlerContext ctx) throws Exception { Integer idValue = ctx.channel().attr(id).get(); #6 // do something with the idValue } @Override protected void channelRead0( ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf) throws Exception { System.out.println("Reveived data"); byteBuf.clear(); } }); bootstrap.option(ChannelOption.SO_KEEPALIVE,true) .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000); #7 bootstrap.attr(id, 123456); #8 ChannelFuture future = bootstrap.connect( new InetSocketAddress("www.manning.com", 80)); #9 future.syncUninterruptibly();使用UDP协议,跟Bootstarp有一点不同的是,不需要bind() 或 connect() 操作
Bootstrap bootstrap = new Bootstrap(); bootstrap.group(new OioEventLoopGroup()).channel(OioDatagramChannel.class) .handler(new SimpleChannelInboundHandler<DatagramPacket>(){ @Override public void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception { // Do something with the packet } }); ChannelFuture future = bootstrap.bind(new InetSocketAddress(0)); future.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture channelFuture) throws Exception { if (channelFuture.isSuccess()) { System.out.println("Channel bound"); } else { System.err.println("Bound attempt failed"); channelFuture.cause().printStackTrace(); } } });