提升异步UDP客户端

4
我已经阅读了boost:asio文档(其中没有提到异步客户端),并在这里查找,但似乎在树林中迷失了方向。
我有一个仿真程序,主循环如下:
for(;;)
{
  a = do_stuff1();
  do_stuff2(a);
}

很容易。

我想做的是修改它,使我拥有:

for(;;)
{
  a = do_stuff1();
  check_for_new_received_udp_data(&b);
  modify_a_with_data_from_b(a,b);
  do_stuff2(a);
}

以下是我的要求:

  1. 我不能因为没有主动监听而丢失数据。即使当服务器发送数据包时,我正在执行do_stuff2(),而不是check_for_new_received_udp_data(),我也不想丢失数据包。
  2. 由于主循环需要以60Hz执行,所以不能让check_for_new_received_udp_data()阻塞超过约2ms。
  3. 服务器将在其他地方运行,并且具有完全不规则的时间表。有时不会有数据,有时我可能会不断收到相同的数据包。

我已经尝试过异步UDP,但那需要调用io_service.run(),这会无限期地阻塞,所以这对我没有帮助。

我考虑过使用超时的阻塞套接字读取,但似乎必须欺骗并退出boost调用才能实现,所以这不是一个可行的方法。

答案是否涉及线程?无论如何,是否有人可以友好地为我指出一个类似的例子?肯定有人做过类似的事情。


+1,不错的第一个问题,欢迎来到SO。 - Sam Miller
长期潜水者,第一次发帖。接下来我得去 Reddit :) - Grommit
2个回答

3
为了避免在 io_service::run() 中阻塞,您可以使用 io_service::poll_one()
关于丢失 UDP 数据包,我认为您运气不好。UDP 不保证传递,并且网络的任何部分都可能决定在有大量流量时丢弃 UDP 数据包。如果您需要确保传递,您需要实现某种形式的流量控制或仅使用 TCP。

1
谢谢。我不太关心网络丢包等问题...我只是不想出现这样的情况:我只有5%的时间在积极查看,因此按设计错过了95%的数据包。如果它们稍后等待收集,那我没问题。 - Grommit
使用异步读取将允许操作系统接收数据包并在调用 runrun_onepollpoll_one 时传递它们。 - TAS
@Grommit 当你使用像poll_one这样的东西时,需要小心的一点是不要让太多的东西排队并且落后于服务器(特别是如果由于某种原因你的主循环必须暂停一段时间)。 - Nathan Monteleone

3
我觉得你的问题在于你仍在同步思考,你需要异步思考。
  1. 对UDP套接字进行异步读取 - 当数据到达时将调用处理程序。
  2. 在该处理程序中处理传入数据。请记住,在处理时,如果您只有一个线程,则没有其他内容分派。这可能完全没问题(UDP消息仍将在网络堆栈中排队...)。
  3. 由于此操作的结果,您可以启动其他异步操作。

如果您需要并行执行实质上不相关或离线的工作,那么将涉及线程。创建一个调用io_service.run()的线程。

如果您需要在异步框架中执行定期工作,请使用计时器

在您的特定示例中,我们可以像这样重新排列事物(伪代码):

read_handler( ... )
{
   modify_a_with_data_from_b(a,b);
   do_stuff2(a);
   a = do_stuff1();
   udp->async_read( ..., read_handler );
}

periodic_handler(...)
{
  // do periodic stuff
  timer.async_wait( ..., periodic_handler );
}

main()
{
   ...
   a = do_stuff1();
   udp->async_read( ..., read_handler )
   timer.async_wait( ..., periodic_handler );

   io_service.run();
}

我相信你的问题中还有其他要求,但你需要找到一个异步解决方案,这只是一个想法。同时,请问自己是否真的需要一个异步框架,或者只需使用同步套接字API。


由于他试图以60hz运行,他需要注意计时器分辨率...看起来asio提供了一个high_resolution_timer typedef,可能可以解决这个问题(没有直接使用过)。 - Nathan Monteleone
@NathanMonteleone:是的。我认为在大多数平台上,截止时间计时器将提供1毫秒的分辨率,但这需要进行验证。如果您可以接受一些抖动但不想累积误差,那也很容易做到。如果您需要更严格的实时要求,这就变得有点复杂了。 - Guy Sirton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接