使用Netty构建只有少数客户端的服务器

时间:2018-01-19 18:41:07

标签: java multithreading netty

我熟悉Netty基础知识,并使用它来构建在TCP上运行的典型应用程序服务器,旨在为许多客户端/连接提供服务。但是,我最近要求构建一个服务器,该服务器设计用于处理少数客户端或大多数时间只处理一个客户端。但客户端是许多设备的网关,因此会为我正在尝试设计的服务器产生大量流量。

我的问题是:

  • 是否有可能/建议在此用例中使用Netty?我看过讨论here

  • 是否可以对管道中的通道处理程序使用多线程EventExecutor,以便通过EventExecutor线程池实现并发性而不是通道EventLoop?它是否会确保来自客户端的一条消息将由一个线程通过所有处理程序处理,而另一条消息则由另一个线程处理?

  • 是否有可用的示例实现?

2 个答案:

答案 0 :(得分:1)

根据io.netty.channel.oio的{​​{3}},如果您没有很多客户,可以使用它。在这种情况下,每个连接都将在一个单独的线程中处理,并在引擎盖下使用Java旧的阻塞IO。看看OioByteStreamChannel::activate

/**
 * Activate this instance. After this call {@link #isActive()} will return {@code true}.
 */
protected final void activate(InputStream is, OutputStream os) {
    if (this.is != null) {
        throw new IllegalStateException("input was set already");
    }
    if (this.os != null) {
        throw new IllegalStateException("output was set already");
    }
    if (is == null) {
        throw new NullPointerException("is");
    }
    if (os == null) {
        throw new NullPointerException("os");
    }
    this.is = is;
    this.os = os;
}

如您所见,oio Stream将在那里使用。

根据你的评论。您可以在向管道添加处理程序时指定EventExecutorGroup,如下所示:

new ChannelInitializer<Channel> {
      public void initChannel(Channel ch) {
          ch.pipeline().addLast(new YourHandler());
      }
}

让我们来看看AbstractChannelHandlerContext

@Override
public EventExecutor executor() {
    if (executor == null) {
        return channel().eventLoop();
    } else {
        return executor;
    }
}

我们在此处看到,如果您未注册EventExecutor,则会在创建ServerBootstrap时使用您指定的子事件组。

new ServerBootstrap()
      .group(new OioEventLoopGroup(), new OioEventLoopGroup())
               //acceptor group          //child group

以下是如何调用来自频道的阅读AbstractChannelHandlerContext::invokeChannelRead

static void invokeChannelRead(final AbstractChannelHandlerContext next, Object msg) {
    final Object m = next.pipeline.touch(ObjectUtil.checkNotNull(msg, "msg"), next);
    EventExecutor executor = next.executor();
    if (executor.inEventLoop()) {
        next.invokeChannelRead(m);
    } else {
        executor.execute(new Runnable() {   //Invoked by the EventExecutor you specified
            @Override
            public void run() {
                next.invokeChannelRead(m);
            }
        });
    }
}

答案 1 :(得分:0)

即使有几个联系,我也会选择NioEventLoopGroup

关于您的问题:

  

是否可以在通道上使用多线程EventExecutor   处理程序中的处理程序,以便代替频道EventLoop,   并发是通过EventExecutor线程池实现的?会吗   确保来自客户端的一条消息将由一个线程处理   通过所有处理程序,而下一条消息由另一个线程处理吗?

Netty的Channel保证对入站或出站邮件的每次处理都将在同一线程中进行。您不必自己破解EventExecutor即可解决此问题。如果提供入站消息不需要长时间的处理,您的代码将看起来像ServerBootstrap的基本用法。您可能会发现调整池中的线程数很有用。