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();
}
}
});