具有Netty的多线程UDP服务器

时间:2015-12-24 16:25:34

标签: java multithreading udp netty

我正在尝试使用Netty实现UDP服务器。想法是只绑定一次(因此只创建一个Channel)。只有一个处理程序初始化此Channel,该处理程序通过ExecutorService在多个线程之间调度传入数据报的处理。

@Configuration
public class SpringConfig {

    @Autowired
    private Dispatcher dispatcher;

    private String host;

    private int port;

    @Bean
    public Bootstrap bootstrap() throws Exception {
        Bootstrap bootstrap = new Bootstrap()
            .group(new NioEventLoopGroup(1))
            .channel(NioDatagramChannel.class)
            .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
            .handler(dispatcher);

        ChannelFuture future = bootstrap.bind(host, port).await();
        if(!future.isSuccess())
            throw new Exception(String.format("Fail to bind on [host = %s , port = %d].", host, port), future.cause());

        return bootstrap;
    }
}

@Component
@Sharable
public class Dispatcher extends ChannelInboundHandlerAdapter implements InitializingBean {

    private int workerThreads;

    private ExecutorService executorService;

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        DatagramPacket packet = (DatagramPacket) msg;

        final Channel channel = ctx.channel();

        executorService.execute(new Runnable() {
            @Override
            public void run() {
                //Process the packet and produce a response packet (below)              
                DatagramPacket responsePacket = ...;

                ChannelFuture future;
                try {
                    future = channel.writeAndFlush(responsePacket).await();
                } catch (InterruptedException e) {
                    return;
                }
                if(!future.isSuccess())
                    log.warn("Failed to write response packet.");
            }
        });
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        executorService = Executors.newFixedThreadPool(workerThreads);
    }
}

我有以下问题:

  1. DatagramPacket类的channelRead方法收到的Dispatcher在被工作线程使用之前是否应该重复?我想知道在channelRead方法返回后该数据包是否被销毁,即使工作线程保留了引用。
  2. 在所有工作线程中共享Channel并让他们同时调用writeAndFlush是否安全?
  3. 谢谢!

1 个答案:

答案 0 :(得分:4)

  1. 不。如果您需要将对象延长时间,请将其转换为其他内容,或者在完成后使用<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> <xsl:key name="tm" match="tm" use="."/> <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template> <xsl:template match="tm[. is key('tm', .)[1]]"> <xsl:copy> <xsl:value-of select="concat(., '&#8482;')"/> </xsl:copy> </xsl:template> </xsl:transform> 然后使用ReferenceCountUtil.retain(datagram)。你也不应该在执行者服务中做ReferenceCountUtil.release(datagram),你应该为任何事情注册一个处理程序。

  2. 是的,渠道对象是线程安全的,可以从许多不同的线程中调用它们。