ChannelFuture channelFuture = serverBootstrap.bind(9000).sync();
我们进入bind方法
/**
* Create a new {@link Channel} and bind it.
*/
public ChannelFuture bind(int inetPort) {
// 调用bind方法,并传入一个InetSocketAddress对象,其中端口号由参数inetPort指定
return bind(new InetSocketAddress(inetPort));
}
这个方法的作用是创建一个新的Channel并绑定到指定的端口。它首先创建一个InetSocketAddress对象,该对象包含了要绑定的端口号,然后调用bind方法将新创建的Channel绑定到该InetSocketAddress。
这个方法的参数inetPort表示要绑定的端口号。通过调用bind(int inetPort)方法,可以方便地将新创建的Channel绑定到指定的端口。
final ChannelFuture regFuture = initAndRegister();
继续跟进去会进到 io.netty.bootstrap.AbstractBootstrap#doBind
private ChannelFuture doBind(final SocketAddress localAddress) {
final ChannelFuture regFuture = initAndRegister();
......
......
}
我们重点关注 initAndRegister
这段代码是NioServerSocketChannel类中的一个私有方法,用于初始化并注册一个新的Channel。让我们逐步解释它:
```java
final ChannelFuture initAndRegister() {
Channel channel = null;
try {
// 使用ChannelFactory创建一个新的Channel实例
channel = channelFactory.newChannel();
// 初始化Channel,包括设置Channel的配置、分配Channel的ID等
init(channel);
} catch (Throwable t) {
if (channel != null) {
// 如果Channel已经创建但是初始化过程中发生了异常,则强制关闭Channel
channel.unsafe().closeForcibly();
// 创建一个新的ChannelPromise并设置异常
return new DefaultChannelPromise(channel, GlobalEventExecutor.INSTANCE).setFailure(t);
}
// 如果Channel还未创建就发生了异常,则创建一个FailedChannel实例,并设置异常
return new DefaultChannelPromise(new FailedChannel(), GlobalEventExecutor.INSTANCE).setFailure(t);
}
// 将Channel注册到EventLoopGroup中,并获取注册结果
ChannelFuture regFuture = config().group().register(channel);
// 如果注册过程中出现了异常
if (regFuture.cause() != null) {
// 如果Channel已经注册成功,直接关闭Channel
if (channel.isRegistered()) {
channel.close();
} else {
// 如果Channel尚未注册成功,强制关闭Channel
channel.unsafe().closeForcibly();
}
}
// 返回注册结果
return regFuture;
}
这个方法的作用是初始化并注册一个新的Channel。它首先使用ChannelFactory
创建一个新的Channel
实例,然后调用init
方法对其进行初始化。如果在初始化过程中发生了异常,则会强制关闭Channel,并返回一个带有异常的ChannelPromise。
接着,它将新创建的Channel
注册到指定的EventLoopGroup
中,并获取注册结果。如果注册过程中出现了异常,则会根据Channel是否已经注册成功来决定是直接关闭Channel还是强制关闭Channel。最后,返回注册结果。
这个方法的设计使得在初始化和注册Channel的过程中能够处理各种异常情况,并保证Channel
的状态正确。
我们重点关注 channelFactory.newChannel();
来会看一下
那就继续 NioServerSocketChannel
的构造函数 ,这里就是 NioServerSocketChannel
初始化的地方 。
@Override
public T newChannel() {
try {
return constructor.newInstance();
} catch (Throwable t) {
throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
}
}
从上面的源码中,我们可以知道必然是无参构造函数 。
无参构造函数
/**
* Create a new instance
*/
public NioServerSocketChannel() {
// 调用另一个构造函数,传入一个新创建的Java NIO ServerSocketChannel实例
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
}
这段代码是NioServerSocketChannel
类的构造函数,它调用了另一个私有构造函数来创建一个新的NioServerSocketChannel
实例。
这个构造函数的作用是创建一个新的NioServerSocketChannel
实例。它通过调用另一个私有构造函数来完成实例的创建过程。在调用私有构造函数时,传入了一个新创建的Java NIO ServerSocketChannel实例作为参数。
这样,NioServerSocketChannel实例就会持有这个Java NIO ServerSocketChannel实例,并在需要时对其进行操作。
`newSocket
我们继续看下 newSocket
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
// 使用指定的SelectorProvider打开一个新的ServerSocketChannel (熟悉的NIO代码)
return provider.openServerSocketChannel();
} catch (IOException e) {
// 如果发生异常,则抛出ChannelException异常
throw new ChannelException("Failed to open a server socket.", e);
}
}
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
这段代码是NioServerSocketChannel
类中的一个私有静态方法,用于使用指定的SelectorProvider创建一个新的ServerSocketChannel。
这个方法的作用是使用指定的SelectorProvider打开一个新的ServerSocketChannel。在Java NIO中,SelectorProvider用于提供新的SelectableChannel实例。方法首先调用指定的SelectorProvider的openServerSocketChannel()方法来创建一个新的ServerSocketChannel实例。如果创建过程中发生了IO异常,则会捕获并抛出ChannelException异常。
provider.openServerSocketChannel() 熟悉的NIO代码
this(newSocket(DEFAULT_SELECTOR_PROVIDER));
/**
* Create a new instance using the given {@link ServerSocketChannel}.
*/
public NioServerSocketChannel(ServerSocketChannel channel) {
// 调用父类构造函数,传入null作为EventLoopGroup参数(因为NioServerSocketChannel没有父类EventLoopGroup),传入给定的ServerSocketChannel实例以及OP_ACCEPT作为感兴趣的事件
super(null, channel, SelectionKey.OP_ACCEPT);
// 创建一个新的NioServerSocketChannelConfig实例,用于配置NioServerSocketChannel的参数
config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}
这段代码是NioServerSocketChannel
类的另一个构造函数,它接受一个ServerSocketChannel
实例作为参数,并调用父类构造函数来初始化NioServerSocketChannel
实例。
这个构造函数的作用是使用给定的ServerSocketChannel
实例来创建一个新的NioServerSocketChannel
实例。
在构造函数中,首先调用了父类AbstractNioMessageChannel
的构造函数,传入了null作为EventLoopGroup
参数(因为NioServerSocketChannel
没有父类EventLoopGroup
)、给定的ServerSocketChannel
实例以及OP_ACCEPT
作为感兴趣的事件。
然后,创建一个新的NioServerSocketChannelConfig
实例,用于配置NioServerSocketChannel
的参数。
SelectionKey.OP_ACCEPT
是Java NIO中SelectableChannel所支持的一种操作兴趣标志。在Netty中,它通常用于NioServerSocketChannel,用于指示对新连接请求的接受操作感兴趣。
具体来说,SelectionKey.OP_ACCEPT
表示SelectableChannel对新连接请求的接受操作感兴趣。当有新的连接请求到达时,Selector会将该事件通知给对应的SelectableChannel,并在之后的事件循环中处理该连接请求。在Netty中,NioServerSocketChannel通常会注册SelectionKey.OP_ACCEPT
事件,以便及时响应新的连接请求。
通过使用这个操作兴趣标志,Netty能够利用Java NIO的非阻塞IO特性,实现高效的TCP服务器端编程,能够处理大量并发的连接请求,提高系统的性能和并发能力。
super(null, channel, SelectionKey.OP_ACCEPT)
这段代码是AbstractNioChannel类的受保护构造函数,用于创建一个新的AbstractNioChannel实例。让我们逐步解释它:
/**
* Create a new instance
*
* @param parent the parent {@link Channel} by which this instance was created. May be {@code null}
* @param ch the underlying {@link SelectableChannel} on which it operates
* @param readInterestOp the ops to set to receive data from the {@link SelectableChannel}
*/
protected AbstractNioChannel(Channel parent, SelectableChannel ch, int readInterestOp) {
// 调用父类构造函数,传入父Channel实例
super(parent);
// 初始化成员变量,保存SelectableChannel和读取操作的兴趣操作
this.ch = ch;
this.readInterestOp = readInterestOp;
try {
// 将SelectableChannel设置为非阻塞模式 (熟悉的NIO方法)
ch.configureBlocking(false);
} catch (IOException e) {
try {
// 发生异常时关闭SelectableChannel
ch.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to close a partially initialized socket.", e2);
}
}
// 抛出ChannelException异常
throw new ChannelException("Failed to enter non-blocking mode.", e);
}
}
这个构造函数用于创建一个新的AbstractNioChannel实例。
它接受三个参数:
在构造函数内部,首先调用了父类构造函数,将父Channel传入以便建立关系。然后,初始化了成员变量,保存了SelectableChannel和读取操作的兴趣标志。
接着,尝试将SelectableChannel
设置为非阻塞模式。如果设置过程中发生IO异常,会关闭SelectableChannel并抛出ChannelException异常。
super(parent);
这段代码是AbstractChannel类的受保护构造函数,用于创建一个新的AbstractChannel实例。让我们逐步解释它:
/**
* Creates a new instance.
*
* @param parent
* the parent of this channel. {@code null} if there's no parent.
*/
protected AbstractChannel(Channel parent) {
// 将父Channel赋值给成员变量parent
this.parent = parent;
// 生成唯一的通道ID
id = newId();
// 创建一个新的Unsafe实例,用于执行底层操作
unsafe = newUnsafe();
// 创建一个新的ChannelPipeline实例,用于存储和处理ChannelHandler
pipeline = newChannelPipeline();
}
这个构造函数用于创建一个新的AbstractChannel
实例。它接受一个参数parent,用于指定这个Channel的父Channel。
在构造函数内部,首先将父Channel赋值给成员变量parent,然后生成一个唯一的通道ID,接着创建一个新的Unsafe实例用于执行底层操作,最后创建一个新的ChannelPipeline实例用于存储和处理ChannelHandler。
newChannelPipeline();
创建一个新的ChannelPipeline实例,用于存储和处理ChannelHandler
/**
* Returns a new {@link DefaultChannelPipeline} instance.
*/
protected DefaultChannelPipeline newChannelPipeline() {
// 创建一个新的DefaultChannelPipeline实例,传入当前的Channel作为参数
return new DefaultChannelPipeline(this);
}
这段代码是AbstractChannel类中的一个受保护方法,用于创建一个新的DefaultChannelPipeline实例。
这个方法用于创建一个新的DefaultChannelPipeline实例,并将当前的Channel作为参数传入。DefaultChannelPipeline是Netty中用于管理ChannelHandler链的默认实现。每个Channel都有自己的ChannelPipeline,用于存储和处理ChannelHandler。调用这个方法会创建一个新的ChannelPipeline实例,并将当前的Channel作为其所属的Channel。
protected DefaultChannelPipeline(Channel channel) {
// 将传入的Channel赋值给成员变量channel
this.channel = ObjectUtil.checkNotNull(channel, "channel");
// 创建一个新的SucceededChannelFuture实例,表示成功的Future
succeededFuture = new SucceededChannelFuture(channel, null);
// 创建一个新的VoidChannelPromise实例,表示空的Promise
voidPromise = new VoidChannelPromise(channel, true);
// 创建一个新的TailContext实例,表示管道中的尾部节点
tail = new TailContext(this);
// 创建一个新的HeadContext实例,表示管道中的头部节点
head = new HeadContext(this);
// 设置头部节点的下一个节点为尾部节点,尾部节点的上一个节点为头部节点
head.next = tail;
tail.prev = head;
}
这段代码是DefaultChannelPipeline类的受保护构造函数,用于创建一个新的DefaultChannelPipeline实例。
这个构造函数用于创建一个新的DefaultChannelPipeline实例。在构造函数内部,首先将传入的Channel赋值给成员变量channel,并创建了一个成功的Future实例(succeededFuture)和一个空的Promise实例(voidPromise)。
接着创建了头部节点(HeadContext)和尾部节点(TailContext),并设置头部节点的下一个节点为尾部节点,尾部节点的上一个节点为头部节点。
这样就构成了一个空的ChannelPipeline链表结构。
ch.configureBlocking(false)
ch.configureBlocking(false);熟悉的NIO代码
ch.configureBlocking(false)
是将一个Java NIO的SelectableChannel
配置为非阻塞模式。
在Java NIO中,SelectableChannel
是一个可以注册到Selector
上并监听IO事件的通道,比如SocketChannel
和ServerSocketChannel
等。在默认情况下,这些通道都是阻塞模式的,意味着当没有数据可读或无法写入时,读取和写入操作会一直阻塞当前线程,直到有数据可用或者通道关闭。
通过调用configureBlocking(false)
方法,可以将这些通道配置为非阻塞模式。在非阻塞模式下,当没有数据可读或无法写入时,读取和写入操作会立即返回而不会阻塞当前线程,这样就可以在单个线程上处理多个通道的IO操作,提高了系统的并发处理能力。
在Netty中,通常会将SelectableChannel
配置为非阻塞模式,以利用Java NIO的非阻塞IO特性,实现高效的事件驱动的网络编程。
NioServerSocketChannel是Netty中用于处理TCP服务器端Socket的通道实现之一。它继承自AbstractNioMessageChannel,是基于Java NIO的ServerSocketChannel的封装。以下是关于NioServerSocketChannel的总结:
构造函数:
初始化和注册:
功能和特性:
底层实现:
综上所述,NioServerSocketChannel是Netty中用于处理TCP服务器端Socket的通道实现,它基于Java NIO,提供了高性能的非阻塞IO操作,并具有初始化、注册、配置参数等功能。