020_对照原生NIO代码看看Netty如何创建ServerSocketChannel

本文详细解析了Netty服务端的初始化流程,从ServerBootstrap的配置开始,到Channel的创建过程,深入探讨了NioServerSocketChannel的构造方法及SelectorProvider的作用,为理解Netty的底层机制提供了清晰的路径。

1、服务端初始化代码

ServerBootstrap serverBootstrap = new ServerBootstrap(); // 相当于Netty的服务器
			
serverBootstrap
			.group(parentGroup, childGroup)
			.channel(NioServerSocketChannel.class)  // 监听端口的ServerSocketChannel
			.option(ChannelOption.SO_BACKLOG, 1024)
			.childHandler(new ChannelInitializer<SocketChannel>() { // 处理每个连接的SocketChannel

				@Override
				protected void initChannel(SocketChannel socketChannel) throws Exception {
					socketChannel.pipeline().addLast(new NettyServerHandler()); // 针对网络请求的处理逻辑
				}
				
			});
	
	ChannelFuture channelFuture = serverBootstrap.bind(50070).sync(); // 同步等待启动服务器监控端口
	
	channelFuture.channel().closeFuture().sync(); // 同步等待关闭启动服务器的结果

点击上面的bind方法,进入如下代码

public ChannelFuture bind(int inetPort) {
    return bind(new InetSocketAddress(inetPort));
}

通过端口号创建一个 InetSocketAddress,继续

public ChannelFuture bind(SocketAddress localAddress) {
    validate();
    return doBind(ObjectUtil.checkNotNull(localAddress, "localAddress"));
}

点击doBind,

private ChannelFuture doBind(final SocketAddress localAddress) {
     final ChannelFuture regFuture = initAndRegister();
     final Channel channel = regFuture.channel();
   //省略
   //。。。。
}

点击initAndRegister方法

final ChannelFuture initAndRegister() {
    Channel channel = null;
	try {
	            channel = channelFactory.newChannel();
	            init(channel);
	 } catch (Throwable t) {
	           //省略
	   //。。。。
}

点击newChannel方法,进入ReflectiveChannelFactory类

@Override
    public T newChannel() {
        try {
            return constructor.newInstance();
        } catch (Throwable t) {
            throw new ChannelException("Unable to create Channel from class " + constructor.getDeclaringClass(), t);
        }
    }

看到这个我们就知道Channel是通过constructor.newInstance()构造的。而constructor的初始化代码如下:

private final Constructor<? extends T> constructor;

    public ReflectiveChannelFactory(Class<? extends T> clazz) {
        ObjectUtil.checkNotNull(clazz, "clazz");
        try {
            this.constructor = clazz.getConstructor();
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Class " + StringUtil.simpleClassName(clazz) +
                    " does not have a public non-arg constructor", e);
        }
    }

看到这里我们就明白了Channel是通过反射创建出来的,是根据我们传入的要给类去拿到默认的构造函数创建。那我们在初始化的时候只在如下这个地方传了个类进去

.channel(NioServerSocketChannel.class)  // 监听端口的ServerSocketChannel

所以应该是调用NioServerSocketChannel类的默认构造函数来创建Channel。

NioServerSocketChannel类

public NioServerSocketChannel() {
        this(newSocket(DEFAULT_SELECTOR_PROVIDER));
    }

其中DEFAULT_SELECTOR_PROVIDER如下:

private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();

点击newSocket方法进入如下:

private static ServerSocketChannel newSocket(SelectorProvider provider) {
    //省略...
    return provider.openServerSocketChannel();
}

通过SelectorProvider.openServerSocketChannel()创建一条ServerSocketChannel 。
构造器继续往下

public NioServerSocketChannel(ServerSocketChannel channel) {
    super(null, channel, SelectionKey.OP_ACCEPT);
    config = new NioServerSocketChannelConfig(this, javaChannel().socket());
}

代码太长了,先就不慢慢记录了。可以参考这篇文章

https://www.jianshu.com/p/c5068caab217
Netty本身是一个基于NIO的高性能网络编程框架,通常不会直接管理Java原生Socket创建的TCP连接,但可以通过一些方式将Java原生Socket与Netty结合使用。 #### 1. 包装原生SocketChannel 可以将Java原生的`java.nio.channels.SocketChannel`包装成Netty的`Channel`对象。以下是一个简单示例: ```java import io.netty.bootstrap.ServerBootstrap; 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.NioServerSocketChannel; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; public class NettyManageNativeSocket { public static void main(String[] args) throws IOException { // 创建Java原生ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.bind(new InetSocketAddress(8080)); // 创建Netty的EventLoopGroup和Bootstrap EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // 可以添加ChannelHandler } }) .option(ChannelOption.SO_BACKLOG, 128) .childOption(ChannelOption.SO_KEEPALIVE, true); // 接受Java原生的连接 while (true) { java.nio.channels.SocketChannel nativeSocketChannel = serverSocketChannel.accept(); // 可以在这里将nativeSocketChannel包装成Netty的Channel并处理 } } finally { workerGroup.shutdownGracefully(); bossGroup.shutdownGracefully(); serverSocketChannel.close(); } } } ``` #### 2. 利用Netty的ChannelPipeline管理 一旦将原生SocketChannel包装成Netty的Channel对象,就可以利用Netty的`ChannelPipeline`来管理连接。`ChannelPipeline`是一个`ChannelHandler`的链表,可以对连接的入站和出站数据进行处理。例如: ```java import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelInboundHandlerAdapter; public class MyHandler extends ChannelInboundHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { // 处理接收到的数据 System.out.println("Received data: " + msg); // 可以继续将数据传递给下一个Handler ctx.fireChannelRead(msg); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 处理异常 cause.printStackTrace(); ctx.close(); } } ``` 在`ChannelInitializer`中添加这个Handler: ```java b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new MyHandler()); } }) ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值