我有一个设置,多个对等体每200毫秒(5fps)广播udp数据包(包含图像)。
虽然接收本地流作为外部流在Windows下工作正常,但相同的代码(Windows XP中的socket->cancel();
除外,请参阅代码中的注释)在Linux下产生相当奇怪的行为:
使用Wireshark,我看到两个本地外部数据包都按照应有的方式到达,连续数据包之间的时间间隔正确。当本地计算机仅侦听单个其他流并且禁用本地流时,该行为也会出现。
这是来自接收器的一些代码(如下所示,有一些更新,谢谢!):
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;
}
当计时器超过20秒时,会返回错误消息“取消操作”,但很难获得有关正在发生的事情的任何其他信息。
任何人都可以识别问题或给我一些提示,以获得有关出错的更多信息吗?任何帮助表示赞赏。
答案 0 :(得分:1)
好的,你正在做的是当你调用receive_with_timeout
时,你正在设置两个异步请求(一个用于recv,一个用于超时)。当第一个完成时,您取消另一个。
但是,您再也不会再调用ioservice::run_one()
来完成回调。取消boost :: asio中的操作时,它会调用处理程序,通常会显示一个错误代码,指示操作已被中止或取消。在这种情况下,我相信你有一个处理程序悬挂一旦你销毁截止日期服务,因为它有一个指向堆栈的指针,以便存储结果。
解决方案是再次调用run_one()以在退出函数之前处理取消的回调结果。您还应该检查传递给超时处理程序的错误代码,并且只在没有错误的情况下将其视为超时。
此外,如果您确实有超时,则需要执行run_one
以便async_recv_from
处理程序可以执行,并报告它已被取消。
答案 1 :(得分:1)
使用Xubuntu 12.04进行全新安装,而不是使用Ubuntu 10.04进行旧安装后,现在一切正常。也许是因为新的安装运行了一个更新的内核,可能改进了网络?无论如何,使用更新版本的发行版重新安装解决了我的问题。
如果其他人使用较旧的内核获得意外的网络行为,我建议在安装了较新内核的系统上进行尝试。