Bootstrap介绍
Bootstrap是开发netty客户端的基础,通过Bootstrap的connect方法来连接服务器端。该方法返回的也是ChannelFuture,
通过这个我们可以判断客户端是否连接成功,以便我们在连接成功之后,做一些其他的事情。但是在调用connect方法前,
我们需要指定EventLoopGroup,channelFactory(不指定这个,就会使用netty默认的channelFactory,但是需要指定channel,初始channel时,
同时会初始化channelFactory),ChannelHandler。这些都是必须指定的,不指定就会报异常.例如不指定channel和channelFactory,
就会报下面的错误。
Bootstrap继承结构
构建Bootstrap
public final class EchoClient {
static final String HOST = System.getProperty("host", "127.0.0.1");
static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));
/** 与server连接的channel */
private static Channel channel;
public static void main(String[] args) throws Exception {
// Configure the client.
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
//不指定channelFactory,就需要指定channel,channel初始化时会指定默认的channelFactory。
.channel(NioSocketChannel.class)
//指定channelFactory,就不需要指定channel了。
//.channelFactory(new ReflectiveChannelFactory<Channel>(NioSocketChannel.class))
.option(ChannelOption.TCP_NODELAY, true)
//指定ChannelHandler
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new EchoClientHandler());
}
});
// Start the client.
b.connect(HOST, PORT).addListener(new ChannelFutureListener() {
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if( future.isSuccess() ){
channel=future.channel();
} else {
}
}
});
while(true){
if(channel!=null && channel.isActive()){
ByteBuf buff = channel.alloc().buffer(64);
buff.writeByte(1);
ChannelFuture channelFuture = channel.writeAndFlush(buff);
channelFuture.addListener(new ChannelFutureListener() {
// write操作完成后调用的回调函数
@Override
public void operationComplete(ChannelFuture future) throws Exception {
if(future.isSuccess()) { // 是否成功
System.out.println("客户端write操作成功");
} else {
System.out.println("客户端write操作失败");
}
}
});
}else{
System.out.println("客户端已经断开连接");
}
}
} finally {
group.shutdownGracefully();
}
}
}
介绍下上面代码涉及到的类:
EventLoop 这个相当于一个处理线程,是Netty接收请求和处理IO请求的线程。
EventLoopGroup 可以理解为将多个EventLoop进行分组管理的一个类,是EventLoop的一个组。
ChannelPipeline 这是Netty处理请求的责任链,这是一个ChannelHandler的链表,而ChannelHandler就是用来处理网络请求的内容的。
ChannelHandler 用来处理网络请求内容,有ChannelInboundHandler和ChannelOutboundHandler两种,ChannlPipeline会从头到尾顺序调用ChannelInboundHandler处理网络请求内容,从尾到头调用ChannelOutboundHandler处理网络请求内容。这也是Netty用来灵活处理网络请求的机制之一,因为使用的时候可以用多个decoder和encoder进行组合,从而适应不同的网络协议。而且这种类似分层的方式可以让每一个Handler专注于处理自己的任务而不用管上下游,这也是pipeline机制的特点。这跟TCP/IP协议中的五层和七层的分层机制有异曲同工之妙。
ChannelFuture
在Netty中的所有的I/O操作都是异步执行的,这就意味着任何一个I/O操作会立刻返回,不保证在调用结束的时候操作会执行完成。因此,会返回一个ChannelFuture的实例,通过这个实例可以获取当前I/O操作的状态。
option设置的参数:
SO_RCVBUF ,SO_SNDBUF
每个TCP socket在内核中都有一个发送缓冲区和一个接收缓冲区,TCP的全双工的工作模式以及TCP的滑动窗口便是依赖于这两个独立的buffer以及此buffer的填充状态。
这两个选项就是来设置TCP连接的两个buffer尺寸的。
SO_SNDBUF
Socket参数,TCP数据发送缓冲区大小。该缓冲区即TCP发送滑动窗口,linux操作系统可使用命令:cat /proc/sys/net/ipv4/tcp_smem查询其大小。
TCP_NODELAY
TCP参数,立即发送数据,默认值为Ture(Netty默认为True而操作系统默认为False)。该值设置Nagle算法的启用,改算法将小的碎片数据连接成更大的报
文来最小化所发送的报文的数量,如果需要发送一些较小的报文,则需要禁用该算法。Netty默认禁用该算法,从而最小化报文传输延时。
SO_KEEPALIVE
Socket参数,连接保活,默认值为False。启用该功能时,TCP会主动探测空闲连接的有效性。可以将此功能视为TCP的心跳机制,需要注意的是:默认的心跳间隔是7200s即2小时。Netty默认关闭该功能。
SO_REUSEADDR
Socket参数,地址复用,默认值False。有四种情况可以使用:
(1).当有一个有相同本地地址和端口的socket1处于TIME_WAIT状态时,而你希望启动的程序
的socket2要占用该地址和端口,比如重启服务且保持先前端口。
(2).有多块网卡或用IP Alias技术的机器在同一端口启动多个进程,但每个进程绑定的本地IP地址不能相同。
(3).单个进程绑定相同的端口到多个socket上,但每个socket绑定的ip地址不同。(4).完全相同的地址和端口的重复绑定。但这只用于UDP的多播,不用于TCP。
SO_LINGER
Socket参数,关闭Socket的延迟时间,默认值为-1,表示禁用该功能。-1表示socket.close()方法立即返回,但OS底层会将发送缓冲区全部发送到对端。0表示socket.close()方法立即返回,OS放弃发送缓冲区的数据直接向对端发送RST包,对端收到复位错误。非0整数值表示调用socket.close()方法的线程被阻塞直到延迟时间到或发送缓冲区中的数据发送完毕,若超时,则对端会收到复位错误。
SO_BACKLOG
Socket参数,服务端接受连接的队列长度,如果队列已满,客户端连接将被拒绝。默认值,Windows为200,其他为128。
SO_BROADCAST
Socket参数,设置广播模式。
Bootstrap执行流程
为了弄清楚Bootstrap如何工作,我们先介绍下AbstractBootstrap:
public abstract class AbstractBootstrap<B extends AbstractBootstrap<B, C>, C extends Channel> implements Cloneable {
volatile EventLoopGroup group;
@SuppressWarnings("deprecation")
private volatile ChannelFactory<? extends C> channelFactory;
private volatile SocketAddress localAddress;
private final Map<ChannelOption<?>, Object> options = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> attrs = new LinkedHashMap<AttributeKey<?>, Object>();
private volatile ChannelHandler handler;
从上面代码可以看出,AbstractBootstrap包含6个属性,这些属性,在我们调用connect方法时,会使用到,我们可以使用一下方法来设置这几个属性的值。
public B group(EventLoopGroup group)
public B channel(Class<? extends C> channelClass)
public B channelFactory(io.netty.channel.ChannelFactory<? extends C> channelFactory)
public B localAddress(SocketAddress localAddress)
public B localAddress(int inetPort)
public B localAddress(String inetHost, int inetPort)
public B localAddress(InetAddress inetHost, int inetPort)
public <T> B option(ChannelOption<T> option, T value)
public <T> B attr(AttributeKey<T> key, T value)
public B handler(ChannelHandler handler)
Bootstrap执行流程