Boostrap

Bootstrap

  • option方法:设置ChannelOption,其将被应用到每个新创建的Channel的ChannelConfig。这些选项将会通过bind()或者connect()方法设置到Channel,不管哪个先被调用。不管哪个先被调用。这个方法在Channel已经被创建后再调用不会有任何的效果。支持的ChannelOption取决于使用的Channel类型。

  • attr方法:指定新创建的Channel的属性值。这些属性值是通过bind()或者connect()方法设置到Channel的,具体取决于谁最先被调用。这个方法在Channel被创建后将不会有任何效果。

ServerBootstrap

  • option
  • childOption
  • attr
  • childAttr
  • handler
  • childHandler

从Channel中引导客户端

(大致就是服务端的ChannelHandler需要建立一个建立一个Bootstra与另一个服务器链接)

假设服务器正在处理一个客户端的请求,这个请求需要服务器充当第三方系统的客户端。当一个应用程序(如一个代理服务器)必须要和组织现有的系统(如Web服务或者数据库)集成时,就可能发生这种情况。在这种情况下,将需要从已经被接受的子Channel中引导一个客户端Channel。

可以创建新的Bootstrap实例,但是这不是最高效的解决方案,因为它要求你为每个新创建的客户端Channel定义另一个EventLoop。这会产生额外的线程,以及在已被接受的子Channel和护短端Channel之间交换数据时不可避免的上下文切换(可以理解这部分)。

一个更好的解决方法是:通过将已被接受的子Channel的EventLoop传递给Bootstrap的group()方法来共享该EventLoop。因为分配给EventLoop的所有Channel都使用同一个线程,所以这避免了额外的线程创建,以及上下文切换。

(可以,比较容易理解)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

BootstrapUtils.runServer(new SimpleChannelInboundHandler<ByteBuf>() {

    ChannelFuture connectChannel;

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Bootstrap bootstrap = new Bootstrap()
                .group(ctx.channel().eventLoop())
                .channel(NioSocketChannel.class)
                .handler(new SimpleChannelInboundHandler<ByteBuf>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
                        System.out.println("Received data");
                    }
                });
        bootstrap.connect(new InetSocketAddress("www.baidu.com", 80));
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
        if (connectChannel.isDone()) {
            // do something with the data
        }
    }
});

编写Netty应用程序的一个一般准则:尽可能地重用EventLoop,以减少线程创建所带来的开销。

ChannelOption与Attribute

可用的ChannelOption包括了底层连接的详细信息,如keep-alive、超时属性、缓冲设置。

Netty应用程序通常与组织的专有软件集成在一起,而像Channel这样的组件可能甚至会在正常的Netty生命周期之外被使用。在某些常用的属性和数据不可用时,Netty提供了属性抽象(一个由Channel和引导类提供的集合)以及属性Key抽象(一个用于插入和获取属性值的泛型类)。使用这些工具,便可以安全地将任何类型的数据项与客户端和服务端Channel(包含ServerChannel的子Channel)相关联了。

(不太理解)

考虑一个用户跟踪用户和Channel质检的关系的服务器应用程序。这可以通过将用户id存储为Channel的一个属性来完成。类似的技术可以被用来基于用户的id将消息路由给用户,或者关闭活动较少的Channel。

(不是太理解,我为什么不用userId到Channel的Map呢?)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

final AttributeKey<Integer> id = AttributeKey.valueOf("ID");

Bootstrap bootstrap = new Bootstrap()
        .group(new NioEventLoopGroup())
        .channel(NioSocketChannel.class)
        .handler(new SimpleChannelInboundHandler<ByteBuf>() {
            @Override
            public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
                Integer integer = ctx.channel().attr(id).get();
                // do something
            }

            @Override
            protected void channelRead0(ChannelHandlerContext ctx, ByteBuf msg) throws Exception {
                System.out.println("Received data");
            }
        })
        .option(ChannelOption.SO_KEEPALIVE, true)
        .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
        .attr(id, 123456);

bootstrap.connect().syncUninterruptibly();

引导数据报

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15

Bootstrap bootstrap = new Bootstrap()
        .group(new OioEventLoopGroup())
        .channel(OioDatagramChannel.class)
        .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
            @Override
            protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
                // do something
            }
        });

bootstrap.bind().addListener((ChannelFutureListener) future -> {

});