2012-08-10 77 views
3

我有一個設置,每個200ms(5fps)廣播udp數據包(包含圖像)的多個對等端。雖然同時接受async_receive_from在Linux下的幾個數據包後停止接收

本地流作爲外部流在Windows下正常工作,同樣的代碼(除Windows XP中的socket->cancel();,見代碼註釋)產生Linux下相當奇怪的行爲:

  • 第一按預期收到另一臺機器發送的少量(5〜7)數據包(本機開始流式傳輸時);
  • 之後,來自另一臺機器的數據包在不規則的長時間間隔(12s,5s,17s,...)之後被接收,或者超時(在20秒後定義)。在某些時刻,如預期的那樣再次出現(3〜4)個分組的突發。
  • 機器本身發送的數據包仍然按照預期收到。

使用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

如果您希望我們提供幫助,請發表一個[簡短,自包含,正確的示例](http://sscce.org/)以說明問題。特別是,如果沒有'Receiver'類定義或'main()',我們無法編譯您發佈的有限代碼。 – 2012-08-11 19:02:24

回答

1

在使用Xubuntu 12.04進行全新安裝而不是使用Ubuntu 10.04進行舊安裝後,現在一切都按預期工作。也許是因爲新的安裝運行了一個更新的內核,可能改進了網絡?無論如何,重新安裝一個更新版本的發行版解決了我的問題。

如果任何人獲得與舊內核的意外的網絡行爲,我會建議安裝一個新的內核嘗試在系統上。

1

好吧,你正在做的是,當你調用receive_with_timeout,你設置的兩個異步請求(一個用於recv的,一個是超時)。當第一個完成時,你取消另一個。

但是,您再也不會調用ioservice::run_one()來允許它的回調完成。當你在boost :: asio中取消一個操作時,它會調用處理程序,通常會顯示一個錯誤代碼,指示該操作已被中止或取消。在這種情況下,我相信一旦你銷燬了截止日期的服務,你就有一個處理程序懸而未決,因爲它有一個指向堆棧的指針來存儲結果。

解決方法是再次調用run_one()以在退出函數之前處理取消的回調結果。您還應該檢查傳遞給您的超時處理程序的錯誤代碼,並且只有在沒有錯誤時纔將其視爲超時。

而且,在你有一個超時的情況下,你需要執行run_one使得async_recv_from處理器可以執行,並報告說,它已被取消。

+0

非常感謝您的建議!不幸的是,他們沒有給我提供解決方案。我希望我能增加更多的東西,但症狀仍然完全一樣。 – 2012-08-10 15:00:10