线程不在Netty UDP服务器中并发执行

时间:2012-05-09 10:43:43

标签: multithreading concurrency udp netty

我正在分析的代码使用Netty NioDatagramChannelFactory创建UDP服务器。 它创建一个带有以下内容的线程池:

ExecutorService threadPool = Executors.newCachedThreadPool();

然后是数据报通道,pipelineFactory&自举:

int workerCount = 10;
DatagramChannelFactory datagramChannelFactory = new NioDatagramChannelFactory(threadPool, workerCount);
ChannelPipelineFactory pipelineFactory = new SNMPTrapsPipeLineFactory();

ConnectionlessBootstrap bootStrap = new ConnectionlessBootstrap(datagramChannelFactory);
bootStrap.setPipelineFactory(pipelineFactory);
bootStrap.bind(new InetSocketAddress(host, port));

在pipelineFactory中,getPipeline()添加了自定义处理程序。

就像在说: Multi-threaded Handling of UDP Messages

只有一个线程处理收到的消息。在日志中,线程名称显示为新I / O数据报工作者#1 ,如:

2012-04-20 09:20:51,853新I / O数据报工作者#1' - '1 INFO [c.e.m.r.s.h.SNMPTrapsRequestHandler:42] messageReceived |处理:V1TRAP [reqestID = 0,...]

我阅读了文档和此条目:Lot of UDP requests lost in UDP server with Netty

然后我根据这些条目更改了一些代码。 现在使用以下命令创建线程池:

int corePoolSize = 5;
ExecutorService threadPool = new OrderedMemoryAwareThreadPoolExecutor(corePoolSize, 1048576, 1048576);

管道工厂和ExecutionHandler:

ExecutionHandler executionHandler = new ExecutionHandler(threadPool);
ChannelPipelineFactory pipelineFactory = new SNMPTrapsPipeLineFactory(executionHandler);

getPipeline()添加了如下描述的处理程序:

public class SNMPTrapsPipeLineFactory implements ChannelPipelineFactory {

    private ExecutionHandler executionHandler = null;

    public SNMPTrapsPipeLineFactory(ExecutionHandler executionHandler) { 
        this.executionHandler = executionHandler;
    }

    @Override
    public ChannelPipeline getPipeline() throws Exception {

        ChannelPipeline pipeline = Channels.pipeline();
        pipeline.addFirst("ExecutorHandler", executionHandler);

        // Here the custom handlers are added
        pipeline.addLast( ... )
    }

现在,我在日志中获得了4个不同的线程名称。它们显示为 pool-2-thread-1 pool-2-thread-2 等...

例如:

2012-05-09 09:12:19,589 pool-2-thread-1 INFO [c.e.m.r.s.h.SNMPTrapsRequestHandler:46] messageReceived |处理:V1TRAP [reqestID = 0,...]

但它们不会同时处理。 messageReceived()下的处理必须在一个线程上完成,以便下一个消息处理下一个消息。 我从不同的客户端向服务器发送了一大堆消息,我得到的日志不是隔行扫描的。我还尝试在messageReceived()中使用Thread.sleep(),并确认前一个。

我错过了什么吗? 有没有办法用Netty实现真正的多线程UDP服务器? 如何让不同的线程同时执行messageReceived()?

2 个答案:

答案 0 :(得分:0)

跳出来的一件事是你将执行处理程序放在第一个中。我相信目的是直到“应用程序”处理程序的整个管道应由执行IO 解码的IO线程执行。

因此,我会断言你想首先添加所有SNMPTrap解码处理程序,然后,当你有一个实际的SNMPTrap时,它会被传递给执行处理程序,执行处理程序又将陷阱传递给实际的消费者陷阱有用的东西。

@Override
public ChannelPipeline getPipeline() throws Exception {

    ChannelPipeline pipeline = Channels.pipeline(
         new SomethingSomethingDecoder(),
         new SNMPTrapDecoder(),
         executionHandler.
         snmpTrapConsumerHandler
    );
}

至少,这就是它在ExecutionHandler javadoc中的显示方式,以上就是我对它的解释。

答案 1 :(得分:0)

根据我的经验以及我对Netty with UDP的理解,通常只有一个线程处理UDP消息进行解码。由于UDP是无会话的,因此只有一个线程可以在一个UDP端口上接收数据并对其进行解码。

一旦解码了数据并将其包装到缓冲区或特定的java对象中,就可以将该对象放入将处理它的线程池中(执行处理程序 - >您的业务处理程序)。然后,一旦将先前解码的数据发布到执行处理程序中,就可以解码UDP端口上即将出现的新数据。

只有在侦听多个端口上的数据时,才能使用创建NioDatagramChannelFactory时可以指定的池的线程。每个端口只有一个线程有意义。即使您在该构造函数中指定了100个worker,如果您配置了一个UDP端口,也只会使用一个。