我一直在搞乱 Boost Asio 几天,但我对这种奇怪的行为感到困惑。请让我解释一下。
计算机A每隔500毫秒向计算机B发送连续udp数据包,计算机B希望以自己的速度读取A的数据包但只想要A的最后一个数据包,显然是最新数据包。
当我这样做时,我注意到了:
mSocket.receive_from(boost :: asio :: buffer(mBuffer),mEndPoint);
我可以获取未处理的OLD数据包(几乎每次都可以)。
这有什么意义吗?我的一个朋友告诉我,套接字保持数据包的缓冲区,因此,如果我的读取频率低于发送者,则可能发生这种情况。 ¡?
所以,第一个问题是如何接收最后一个数据包并丢弃我错过的数据包?
后来我尝试使用Boost文档的异步示例,但发现它没有做我想要的。
http://www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/tutorial/tutdaytime6.html
据我所知, async_receive_from 应该在数据包到达时调用方法“handle_receive”,并且在服务之后适用于第一个数据包“运行”即可。
如果我想继续监听端口,我应该在句柄代码中再次调用 async_receive_from 。正确?
但我发现的是我开始一个无限循环,它不会等到下一个数据包,它只是一次又一次地输入“handle_receive”。
我没有做服务器应用程序,很多事情正在发生(它是游戏),所以我的第二个问题是,我是否必须使用线程正确使用异步接收方法,是否有一些示例线程和异步接收?
答案 0 :(得分:2)
一种选择是利用以下事实:当UDP套接字的本地接收缓冲区填满时,随后接收的数据包将把旧的数据包推出缓冲区。您可以将本地接收缓冲区大小设置为足以容纳一个数据包,但不能设置为两个。这将使最新的数据包到达总是导致前一个数据包被丢弃。当您使用receive_from询问数据包时,您将获得最新的(也是唯一的)数据包。
以下是使用Boost更改接收缓冲区大小的API文档:
示例似乎是错误的,因为它显示了一个tcp套接字而不是一个udp套接字,但是将其更改回udp应该很容易(明显的变化应该是正确的)。
答案 1 :(得分:1)
使用Windows(当然是XP,Vista和7);如果将recv缓冲区大小设置为零,则只有在数据报到达时有recv挂起时才会收到数据报。这可以做你想要的,但如果你在最后一个数据报到达之后发布你的recv,你将不得不等待下一个......
由于你正在做一个游戏,恕我直言,使用基于UDP而不是UDP本身构建的东西要好得多。看看ENet支持UDP上的可靠数据,以及UDP上不可靠的“序列”数据。对于不可靠的序列数据,您只能获得“最新”数据。或类似RakNet之类的内容可能对您有用,因为它可以处理很多游戏内容,还包含类似于ENet序列数据的内容。
您应该记住的另一件事是,使用原始UDP,您可能无法获得这些数据报,并且您可能不止一次获得这些数据报。因此,如果您不使用为您排序数据的内容,那么您可能无论如何都需要自己的序列号。
答案 2 :(得分:0)
P2engine是一个灵活高效的平台,可让您更轻松地进行p2p系统开发。可靠的UDP,消息传输,消息调度,快速和安全的信号/插槽......
答案 3 :(得分:0)
你的方式错了。接收端有一个FIFO队列。一旦队列被填满,新的到达数据包将被丢弃。
所以你需要在接收器上做的只是尽可能快地读取数据包并在它们到达时处理它们。
您的接收端应该能够轻松地每隔500毫秒处理一次数据包。我会说你的代码中有一个错误,而且你的描述是肯定的。
可能是这样,请确保在handle_receive中,如果没有错误,只调用async_receive_from。
答案 4 :(得分:0)
我认为我有同样的问题,要解决我读bytes_available
的问题并与数据包宽度进行比较,直到我收到最后一个包:
boost::asio::socket_base::bytes_readable command(true);
socket_server.io_control(command);
std::size_t bytes_readable = command.get();