您当前的位置: 首页 > 

恐龙弟旺仔

暂无认证

  • 0浏览

    0关注

    282博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Netty源码解析-ServerBootstrap与BootStrap初探

恐龙弟旺仔 发布时间:2021-12-13 20:34:58 ,浏览量:0

前言:

    在之前系列的介绍了NIO相关的文章之后,我们可以在此基础上进行Netty的学习了。建议不太了解NIO的同学,可以先看下相关系列文章。Netty的本质还是NIO。

    Netty笔者之前也有学习过,主要是跟着这本书进行学习的,所以主要还是使用方面的,当然,学习完成之后,也从来没有使用到过,所以到目前为止也忘记的七七八八了。

    记得有一次面试,面试官问我,你觉得Netty哪里好,支支吾吾的说了半天,就是觉得架构好,怎么个好法呢?具体细节又是蒙了。

    针对这种典型的、通用的、高效的网络架构,个人觉得还是有必要好好学习一下的,不仅仅是使用层面的,而是更应该从源码角度,深入了解其架构设计,这样再跟别人聊的时候才有底气去说。

    笔者使用的是Netty-4.1系列的代码,代码量还是非常大的。如果我们全部看完的话,深入每个细节去了解的话,很容易就陷入到代码细节的海洋中。所以我们一定要抓住主干部分,先去了解主要流程节点,然后再看其细节。

1.ServerBootStrap示例

    ServerBootStrap作为服务端,主要用于接收客户端连接请求,以及客户端发送的信息,并返回响应给客户端。主要示例代码如下:(代码主要来自于网络,做了一点修改)

public class HelloServer {
    private static final int PORT = 18080;

    public static void main(String[] args) {

        // 设置boss线程池
        EventLoopGroup bossGroup = new NioEventLoopGroup(1);
        // 设置work线程池
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup)
                    // 指定处理channel
                    .channel(NioServerSocketChannel.class)
                    // 设置属性值
                    .option(ChannelOption.SO_BACKLOG, 100)
                    // 指定server处理Handler
                    .handler(new LoggingHandler(LogLevel.INFO))
                    // 指定client处理Handler
                    .childHandler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("frame", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter()));
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            pipeline.addLast("handler", new HelloServerHandler());
                        }
                    });
            // 绑定端口监听
            ChannelFuture f = b.bind(PORT).sync();
            // 监听服务器关闭监听
            f.channel().closeFuture().sync();
            // 可以简写为
            /* b.bind(portNumber).sync().channel().closeFuture().sync(); */
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}

public class HelloServerHandler extends SimpleChannelInboundHandler {

    /**
     * 当连接建立时,执行的方法
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client" + ctx.channel().remoteAddress() + "connected");
        ctx.writeAndFlush("welcome to our server\n");
        super.channelActive(ctx);
    }

    /**
     * 当失去连接时,执行的方法
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client" + ctx.channel().remoteAddress() + "disconnected");
        super.channelActive(ctx);
    }

    /**
     * 当获取到client发送过来的消息时,执行的方法
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("client " + ctx.channel().remoteAddress() + " say: " + msg);
        ctx.writeAndFlush("msg received\n");
    }
}

 2.BootStrap示例

    BootStrap作为客户端,主要用于发起对服务端的连接,发送信息到服务端和接收服务端的响应。代码示例如下:

public class HelloClient {
    private static String HOST = "127.0.0.1";
    private static int PORT = 18080;

    public static void main(String[] args) {
        // 设置线程池
        EventLoopGroup group = new NioEventLoopGroup(1);
        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    // 设置执行channel
                    .channel(NioSocketChannel.class)
                    // 设置客户端处理Handler
                    .handler(new ChannelInitializer() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ChannelPipeline pipeline = ch.pipeline();
                            pipeline.addLast("frame", new DelimiterBasedFrameDecoder(1024, Delimiters.lineDelimiter()));
                            pipeline.addLast("decoder", new StringDecoder());
                            pipeline.addLast("encoder", new StringEncoder());
                            pipeline.addLast("handler", new HelloClientHandler());
                        }
                    });
            // 连接服务端
            Channel ch = b.connect(HOST, PORT).sync().channel();
            // 控制台输入
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            for (; ; ) {
                String line = in.readLine();
                if (line == null) {
                    continue;
                }
                ch.writeAndFlush(line + "\r\n");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            group.shutdownGracefully();
        }
    }
}

public class HelloClientHandler extends SimpleChannelInboundHandler {
    /**
     * 当连接到server成功时,执行的方法
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client active");
        super.channelActive(ctx);
    }

    /**
     * 当与server的连接断开时,执行的方法
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        System.out.println("client close");
        super.channelInactive(ctx);
    }

    /**
     * 接收到服务端的信息时执行的方法
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println("receive server msg: " + msg);
    }
}

以上客户端与服务端,演示了一个客户端带有输入框,可以不断发送消息到服务端,而服务端接收到消息后,打印到窗口并返回一个已接收到请求的响应。整个如下所示:

client:
// 连接到服务端
client active
receive server msg: welcome to our server

// 发送消息-1
see you see me
// 接收到响应-1
receive server msg: msg received

// 发送消息-2
see we together
// 接收到响应-2
receive server msg: msg received
server:

// 接收到客户端的连接
client/127.0.0.1:1768connected

// 接收到客户端信息-1
client /127.0.0.1:1768 say: see you see me

// 接收到客户端信息-2
client /127.0.0.1:1768 say: see we together

以上就是一个对话框的简单示例。

3.AbstractBootStrap分析

    通过分析ServerBootStrap和BootStrap的源码,可以看出

 这两个类都继承了AbstractBootstrap,所以我们先来分析下该类的一些公共方法

public abstract class AbstractBootstrap implements Cloneable {
 
    // 上面示例中的boss线程池和work线程池
    volatile EventLoopGroup group;
	// Channel工厂,用于创建channel对象
    private volatile ChannelFactory, Object> options = new LinkedHashMap, Object> attrs = new ConcurrentHashMap, Object> childOptions = new LinkedHashMap, Object> childAttrs = new ConcurrentHashMap, Object>[] currentChildOptions;
        synchronized (childOptions) {
            currentChildOptions = childOptions.entrySet().toArray(EMPTY_OPTION_ARRAY);
        }
        final Entry            
关注
打赏
1655041699
查看更多评论
0.0362s