我正在分析的代码使用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()?
答案 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端口,也只会使用一个。