BootStrap
client demo
来源 netty in action
package com.zc.netty.action.demo.time;
import io.netty.bootstrap.Bootstrap;
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.NioSocketChannel;
public class TimeClient {
public static void main(String[] args) throws Exception {
String host = "127.0.0.1";// args[0];
int port = 8080;//Integer.parseInt(args[1]);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap(); // (1)
b.group(workerGroup); // (2)
b.channel(NioSocketChannel.class); // (3) 设置 channel
b.option(ChannelOption.SO_KEEPALIVE, true); // (4) 配置通道选项ChannelOption,此处设置连接通道保持连接
b.handler(new ChannelInitializer<SocketChannel>() {// 我们往往会设置一个 ChannelInitializer抽象类的一个实现类的对象,在这个类的实现方法中我们逐一设置用户定义的各种处理器对象
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new TimeClientHandler());
}
});
// 启动客户端
ChannelFuture f = b.connect(host, port).sync(); // (5)
// 等待连接关闭
f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
System.out.println("over");
while (true) {
}
}
}
}
客户端启动
- BootStrap客户端启动
- new Bootstrap() 创建客户端对象
- b.channel(NioSocketChannel.class) 设置channel
- channelFactory(new ReflectiveChannelFactory<C>(channelClass));// 默认创建的 channelFactory是 ReflectiveChannelFactory
- new ReflectiveChannelFactory<C>(channelClass): 根据传入的NioSocketChannel.class反射创建该实例
- channelFactory():将上一步创建的ReflectiveChannelFactory设置到BootStrap中并返回Bootstrap用于链式调用
- b.option(ChannelOption.SO_KEEPALIVE, true)
- 加锁设置属性到bootstrap.options中
- b.handler() 将handler设置到bootstrap中
- b.connect(host, port)
- connect(InetSocketAddress.createUnresolved(inetHost, inetPort))
- validate()校验group和channelFactory属性必须配置,校验config.handler必填
- doResolveAndConnect(remoteAddress, config.localAddress())
- initAndRegister();// 初始化和注册,返回 ChannelFuture,不会阻塞
- channelFactory.newChannel();// 创建 socketChannel,如 NioSocketChannel
- 构造方法中:
- id = newId();// 给每个 channel 分配一个唯一 id
- unsafe = newUnsafe();// 每个 channel 内部需要一个 Unsafe 的实例,封装了对 Java 底层 Socket 的操作
- pipeline = newChannelPipeline();// 每个 channel 内部都会创建一个 pipeline
- init(channel) 对 Channel进行初始化设置
- channel.pipeline() 获取channel中的pipeline
- p.addLast(config.handler()) // 将配置的handler添加到pipeline中
- 获取bootstrap.options对象
- setChannelOptions(channel, options, logger);// 加锁,将用户配置的选项列表设置到通道对象中
- 获取bootstrap.attrs对象
- channel.attr((AttributeKey<Object>) e.getKey()).set(e.getValue());// 将用户配置的属性类型设置到通道对象中
- ChannelFuture regFuture = config().group().register(channel);// 将初始化过的 NioServerSocketChannel 注册到配置的 EventLoopGroup对象上,返回 ChannelFuture对象
- MultithreadEventLoopGroup.register()
- next().register(channel)
- register(new DefaultChannelPromise(channel, this));// 将 channel封装成 promise,然后再 注册
- register()
- promise.channel().unsafe().register(this, promise);// 从 promise中取出 channel,从 channel中获取 unsafe
- eventLoop.execute()
- doRegister()
- selectionKey = javaChannel().register(eventLoop().unwrappedSelector(), 0, this);
- if (regFuture.cause() != null) {// 若注册失败则关闭连接通道
- b.sync()