[英]udp (boost::asio) read error after async_receive_from
[英]async_receive_from stops receiving after a few packets under Linux
我有一個設置,多個對等體每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秒時,將返回錯誤消息“取消操作”,但很難獲得有關正在發生的事情的任何其他信息。
任何人都可以識別問題或給我一些提示,以獲得有關出錯的更多信息嗎? 任何幫助表示贊賞。
好的,你正在做的是當你調用receive_with_timeout
,你正在設置兩個異步請求(一個用於recv,一個用於超時)。 當第一個完成時,您取消另一個。
但是,您永遠不會再次調用ioservice::run_one()
以允許它的回調完成。 取消boost :: asio中的操作時,它會調用處理程序,通常會顯示一個錯誤代碼,指示操作已被中止或取消。 在這種情況下,我相信你有一個處理程序懸掛一旦你銷毀截止日期服務,因為它有一個指向堆棧的指針,以便存儲結果。
解決方案是再次調用run_one()以在退出函數之前處理已取消的回調結果。 您還應該檢查傳遞給超時處理程序的錯誤代碼,並且只在沒有錯誤時將其視為超時。
此外,在您確實有超時的情況下,您需要執行run_one
以便async_recv_from
處理程序可以執行,並報告它已被取消。
使用Xubuntu 12.04進行全新安裝而不是使用Ubuntu 10.04進行舊安裝后,現在一切都按預期工作。 也許是因為新的安裝運行了一個更新的內核,可能改進了網絡? 無論如何,使用更新版本的發行版重新安裝解決了我的問題。
如果其他人使用較舊的內核獲得意外的網絡行為,我建議在安裝了較新內核的系統上進行嘗試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.