C++ 在Linux下,async_receive_from在几个数据包之后停止接收
我有一个设置,每200ms(5fps)有多个对等点广播udp数据包(包含图像) 在Windows下,当以外部流的形式接收本地流时,相同的代码(除了Windows XP中的C++ 在Linux下,async_receive_from在几个数据包之后停止接收,c++,linux,udp,boost-asio,C++,Linux,Udp,Boost Asio,我有一个设置,每200ms(5fps)有多个对等点广播udp数据包(包含图像) 在Windows下,当以外部流的形式接收本地流时,相同的代码(除了Windows XP中的socket->cancel();,请参见代码中的注释)在Linux下会产生相当奇怪的行为: 由另一台机器发送的前几个(5~7)数据包(当该机器开始流传输时)按预期接收 在此之后,在不规则的长间隔(12s、5s、17s等)后接收来自另一台机器的数据包,或获得超时(在20秒后定义)。在某些时刻,再次出现预期的(3~4)个数据包的
socket->cancel();
,请参见代码中的注释)在Linux下会产生相当奇怪的行为:
- 由另一台机器发送的前几个(5~7)数据包(当该机器开始流传输时)按预期接收李>
- 在此之后,在不规则的长间隔(12s、5s、17s等)后接收来自另一台机器的数据包,或获得超时(在20秒后定义)。在某些时刻,再次出现预期的(3~4)个数据包的突发
- 机器本身发送的数据包仍按预期接收
Receiver::Receiver(端口p)
{
这个->端口=p;
此->停止=错误;
}
int Receiver::run()
{
io_服务io_服务;
boost::asio::ip::udp::套接字(
io_服务,
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
这个->端口);
当(!停止)
{
常数int bufflength=65000;
int超时=20000;
char sockdata[bufflength];
boost::asio::ip::udp::endpoint远程\u端点;
int rcvd;
bool read\u success=此->接收\u超时(
sockdata、bufflength、rcvd和socket、远程_端点、超时);
如果(读成功)
{
std::cout好的,您正在做的是,当您调用receive\u with\u timeout
时,您正在设置两个异步请求(一个用于recv,一个用于超时)。当第一个请求完成时,您将取消另一个请求
但是,您永远不会调用ioservice::run_one()
再次调用,以允许其回调完成。当您取消boost::asio中的操作时,它会调用处理程序,通常带有一个错误代码,指示该操作已中止或取消。在这种情况下,我相信在销毁deadline服务后,会有一个处理程序悬空,因为它在堆栈上有一个指向st的指针结果如何
解决方案是在退出函数之前再次调用run_one()以处理取消的回调结果。您还应该检查传递给超时处理程序的错误代码,并且只有在没有错误时才将其视为超时
另外,如果你确实有一个超时,你需要执行run\u one
,这样来自处理程序的async\u recv\u可以执行,并报告它被取消了。在使用Xubuntu 12.04而不是使用Ubuntu 10.04进行了一次干净的安装之后,一切都按照预期进行了。可能是因为新的inst所有这些都运行一个更新的内核,可能是通过改进的网络?无论如何,用更新版本的发行版重新安装解决了我的问题
如果其他人在使用旧内核时出现意外的网络行为,我建议在安装了新内核的系统上尝试。非常感谢您的建议!不幸的是,他们没有为我提供解决方案。我希望我可以添加更多内容,但症状仍然完全相同。发布演示如果您希望我们提供帮助,则会出现问题。特别是,如果没有Receiver
类定义或main()
,我们无法编译您发布的有限代码。
Receiver::Receiver(port p)
{
this->port = p;
this->stop = false;
}
int Receiver::run()
{
io_service io_service;
boost::asio::ip::udp::socket socket(
io_service,
boost::asio::ip::udp::endpoint(boost::asio::ip::udp::v4(),
this->port));
while(!stop)
{
const int bufflength = 65000;
int timeout = 20000;
char sockdata[bufflength];
boost::asio::ip::udp::endpoint remote_endpoint;
int rcvd;
bool read_success = this->receive_with_timeout(
sockdata, bufflength, &rcvd, &socket, remote_endpoint, timeout);
if(read_success)
{
std::cout << "read succes " << remote_endpoint.address().to_string() << std::endl;
}
else
{
std::cout << "read fail" << std::endl;
}
}
return 0;
}
void handle_receive_from(
bool* toset, boost::system::error_code error, size_t length, int* outsize)
{
if(!error || error == boost::asio::error::message_size)
{
*toset = length>0?true:false;
*outsize = length;
}
else
{
std::cout << error.message() << std::endl;
}
}
// Update: error check
void handle_timeout( bool* toset, boost::system::error_code error)
{
if(!error)
{
*toset = true;
}
else
{
std::cout << error.message() << std::endl;
}
}
bool Receiver::receive_with_timeout(
char* data, int buffl, int* outsize,
boost::asio::ip::udp::socket *socket,
boost::asio::ip::udp::endpoint &sender_endpoint, int msec_tout)
{
bool timer_overflow = false;
bool read_result = false;
deadline_timer timer( socket->get_io_service() );
timer.expires_from_now( boost::posix_time::milliseconds(msec_tout) );
timer.async_wait( boost::bind(&handle_timeout, &timer_overflow,
boost::asio::placeholders::error) );
socket->async_receive_from(
boost::asio::buffer(data, buffl), sender_endpoint,
boost::bind(&handle_receive_from, &read_result,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred, outsize));
socket->get_io_service().reset();
while ( socket->get_io_service().run_one())
{
if ( read_result )
{
timer.cancel();
}
else if ( timer_overflow )
{
//not to be used on Windows XP, Windows Server 2003, or earlier
socket->cancel();
// Update: added run_one()
socket->get_io_service().run_one();
}
}
// Update: added run_one()
socket->get_io_service().run_one();
return read_result;
}