зачем использовать цикл netty writeAndFlush для отправки DatagramPacket на некоторое время в спящем потоке? - PullRequest
0 голосов
/ 20 апреля 2019

Есть проблема, которая смущала меня долгое время. то есть когда я использую цикл netty writeAndFlush для отправки DatagramPacket на мой сервер udp, большинство сообщений теряются. но если я сплю поток некоторое время, все сообщения будут доставлены. как это:

public static void main(String[] args) throws InterruptedException {
    int count = 3000;
    AtomicInteger integer = new AtomicInteger(count);
    AtomicInteger countInteger = new AtomicInteger();
    Bootstrap bootstrap = new Bootstrap();
    EventLoopGroup group = new NioEventLoopGroup();
    ChannelFuture channelFuture = bootstrap.group(group)
            .channel(NioDatagramChannel.class)
            .option(ChannelOption.SO_BROADCAST, true)
            .option(ChannelOption.SO_REUSEADDR, true)
            .option(ChannelOption.SO_RCVBUF, 1024 * 1024)
            .option(ChannelOption.SO_SNDBUF, 1024 * 1024)
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)
            .handler(new ChannelInitializer<Channel>() {

                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ch.pipeline().addLast(new WakeupMessageEncoder())
                            .addLast(new WakeupMessageReplyDecoder())
                            .addLast(new SimpleChannelInboundHandler<WakeupMessageReply>() {

                                @Override
                                protected void channelRead0(ChannelHandlerContext ctx, WakeupMessageReply reply) throws Exception {
                                    countInteger.getAndIncrement();
                                    System.out.println(reply);
                                }
                            })
                            ;
                }
            }).bind(0).sync();
    Channel channel = channelFuture.channel();
    long s = System.currentTimeMillis();
    for (int i = 0; i < count; i++) {
        //TimeUnit.NANOSECONDS.sleep(1);
        WakeupMessage message = new WakeupMessage(UUID.randomUUID().toString(), "192.168.0.3:12000", "89860918700328360182", "test message" + i);
        channel.writeAndFlush(message).addListener(f -> integer.decrementAndGet());
    }
    while (true) {
        if (integer.get() <= 0) {
            break;
        }
    }
    try {
        channel.closeFuture();
        System.out.println("done:" + (System.currentTimeMillis() - s) + "ms");
        System.out.println(countInteger);
    }finally {
        group.shutdownGracefully();
    }
} 

Я отправляю 3000 сообщений, но получаю мало ... как это: 1744 сообщения но если я сплю нить, как это:

for (int i = 0; i < count; i++) {
    TimeUnit.NANOSECONDS.sleep(1);
    WakeupMessage message = new WakeupMessage(UUID.randomUUID().toString(), "192.168.0.3:12000", "89860918700328360182", "test message" + i);
    channel.writeAndFlush(message).addListener(f -> integer.decrementAndGet());
}

Я получу все повторы с сервера udp.

так почему я должен спать нить ???

Ответы [ 2 ]

1 голос
/ 20 апреля 2019

Пакеты дейтаграмм (UDP) не имеют гарантированной доставки и могут быть отброшены, если вы отправите слишком быстро. Есть много возможных причин для этого, в вашем случае вы, скорее всего, заполняете буфер отправки или буфер приема или оба. Эта статья более детально описана.

0 голосов
/ 20 апреля 2019

Другой вариант - sync() слушатель, когда вы пишете и сбрасываете, т.е.

channel.writeAndFlush(message).addListener(f -> integer.decrementAndGet()).sync();

В моем тестировании, это получает все 3000 ответов с гораздо меньшим затраченным временем, чем сон. Для локального UDP-эхо-сервера на моем ноутбуке:

  • Всего прошло со сном: 3,758мс
  • Всего прошло с синхронизацией: 407 мс

Однако, как отмечает @ewramner, ни один из вариантов не гарантирует , вы получите все 3000 ответов.

...