簡體   English   中英

為什么這個程序沒有收到預期的UDP數據包?

[英]Why does this program not receive the expected UDP packets?

我試圖使用Boost asio接收UDP數據包。 我的代碼基於asio文檔中的阻塞UDP客戶端示例

我試圖從C6655 TI DSP接收類似BOOTP的UDP數據包,這些數據包以3秒的間隔傳輸。 我有Wireshark看着我的程序正在監聽的相同接口,它可以看到數據包到達(參見下面的確切數據包數據,從Wireshark導出)。 數據包並非真正來自DSP,我使用tcpdump捕獲了一個數據包,並且我正在使用帶有的Raspberry Pi模擬它。

但是,我的程序沒有收到數據包。 它有4秒的超時(因為DSP每3秒播放一次)。 如果它達到超時,它會打印一條消息,否則它應該打印接收的字節數。 該程序的完整(可編譯)源代碼如下(約100行)。

使用參數192.168.5.122 67 4000調用該命令,這意味着在192.168.5.122:67上偵聽超時4000毫秒。

編輯:除了下面的代碼,我還嘗試了這個作為我的端點: udp::endpoint listen_endpoint(boost::asio::ip::address_v4::any(), atoi(argv[2])); 以及某處搜索結果建議的IP地址0.0.0.0

我還添加了以下內容無濟於事:

boost::asio::socket_base::broadcast option(true);
socket_.set_option(option);

我有一個能夠正確接收此數據包的程序,使用Berkeley套接字編寫。 除了綁定到INADDR_ANY之外,我沒有做任何特別的事情。

這是完整的程序:

//
// blocking_udp_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <iostream>

using boost::asio::deadline_timer;
using boost::asio::ip::udp;

class listener
{
public:
    listener(const udp::endpoint& listen_endpoint)
        : socket_(io_service_, listen_endpoint)
        , deadline_(io_service_)
    {
        deadline_.expires_at(boost::posix_time::pos_infin);
        check_deadline();
    }

    std::size_t receive(const boost::asio::mutable_buffer& buffer, boost::posix_time::time_duration timeout, boost::system::error_code& ec)
    {
        deadline_.expires_from_now(timeout);
        ec = boost::asio::error::would_block;
        std::size_t length = 0;
        socket_.async_receive(boost::asio::buffer(buffer), boost::bind(&listener::handle_receive, _1, _2, &ec, &length));

        // TODO: The following do/while is hinky. Does run_one() need to happen before the comparison?
        do io_service_.run_one();
        while (ec == boost::asio::error::would_block);

        return length;
    }

private:
    void check_deadline()
    {
        if (deadline_.expires_at() <= deadline_timer::traits_type::now())
        {
            // cancel() won't work on XP. Something about using close() instead... Look it up. I'm doing this on Win10.
            socket_.cancel();
            deadline_.expires_at(boost::posix_time::pos_infin);
        }
        deadline_.async_wait(boost::bind(&listener::check_deadline, this));
    }

    static void handle_receive(const boost::system::error_code& ec, std::size_t length, boost::system::error_code* out_ec, std::size_t* out_length)
    {
        *out_ec = ec;
        *out_length = length;
    }

private:
    boost::asio::io_service io_service_;
    udp::socket socket_;
    deadline_timer deadline_;
};

int main(int argc, char* argv[])
{
    try
    {
        if (argc != 4)
        {
            std::cerr << "Usage: blocking_udp_timeout <listen_addr> <listen_port> <timeout_ms>\n";
            return 1;
        }

        udp::endpoint listen_endpoint(boost::asio::ip::address::from_string("0.0.0.0"), atoi(argv[2]));
        std::cout << "Endpoint: " << listen_endpoint << std::endl;

        auto timeout = atoi(argv[3]);
        std::cout << "Timeout : " << timeout << std::endl;

        listener c(listen_endpoint);

        for (;;)
        {
            char data[1024];
            boost::system::error_code ec;
            auto n = c.receive(boost::asio::buffer(data), boost::posix_time::milliseconds{timeout}, ec);

            if (ec)
            {
                std::cout << "Receive error: " << ec.message() << "\n";
            }
            else
            {
                std::cout << "Received " << n << " bytes." << std::endl;
            }
        }
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

這是我想要收到的數據包。 這包括以太網幀:

0000   ff ff ff ff ff ff c4 ed ba aa 28 35 08 00 45 00  ..........(5..E.
0010   01 48 00 01 00 00 10 11 a9 a5 00 00 00 00 00 00  .H..............
0020   00 00 00 44 00 43 01 34 00 00 01 01 06 00 12 34  ...D.C.4.......4
0030   56 78 00 01 00 00 00 00 00 00 00 00 00 00 00 00  Vx..............
0040   00 00 00 00 00 00 c4 ed ba aa 28 35 00 00 00 00  ..........(5....
0050   00 00 00 00 00 00 74 69 2d 62 6f 6f 74 2d 74 61  ......ti-boot-ta
0060   62 6c 65 2d 73 76 72 00 00 00 00 00 00 00 00 00  ble-svr.........
0070   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0080   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0090   00 00 00 00 00 00 74 69 2d 62 6f 6f 74 2d 74 61  ......ti-boot-ta
00a0   62 6c 65 2d 30 30 30 37 00 00 00 00 00 00 00 00  ble-0007........
00b0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00c0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00d0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00e0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00f0   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0100   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0110   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0120   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0130   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0140   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0150   00 00 00 00 00 00                                ......

我有一個可以接收此數據包的Berkeley套接字實現(我已經刪除了錯誤處理和其他錯誤代碼):

{
    struct sockaddr_in servaddr;
    socklen_t len;
    char mesg[RECV_BUFFER_LENGTH];

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(67);
    bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));
    n = recvfrom(sockfd, mesg, RECV_BUFFER_LENGTH, 0, NULL, &len);
}

考慮在socket_.cancel()之后但在下一次調用socket_.async_receive()之前發生了什么。 如果有任何數據到達,則沒有為套接字分配“接收處理程序”。 當計時器到期時,它會導致run_once()被調用3次(因為每個async_wait()expires_at()和其他一些導致取消已經分配的處理程序並導致已經分配的處理程序被發布到運行隊列,錯誤代碼為operation_aborted )。

您還沒有提到超時設置的內容。 基於代碼的示例(來自Boost文檔的示例)將超時設置為10秒,但您可以將其配置為可配置。 如果超時太緊,這將導致旋轉(post-> cancel previous-> call previous handler-> post-> etc。)並且可能在接收數據包時調用socket_.cancel() 如果是這種情況,你就不必用廣播進行測試。 您也可以通過點對點連接查看它。

編輯 :在使用長超時(4000毫秒)和您的確切代碼時,我能夠收到已發送的廣播。 我不得不安裝“傳統”netcat,因為BSD netcat壞了。 但是下面的一行有效

echo "hello world" | nc.traditional -b -u 192.168.XXX.255 1500

XXX.255不是字面意思是“XXX.255”。 這是我當地的廣播地址。 nc.bsd中的-b選項被破壞了(你可以看看為什么你用上面的選項划分nc.bsd)。

unix stackexchange nc.traditional有一個很好的例子,說明其他人如何弄清楚為什么nc.bsd不能做UDP廣播(-b選項什么都不做)。

PackEth無法發送廣播或ptp流量,因此我不會將其用作衡量您是否可以發送廣播流量的指標。 不可否認,我對它沒有多少經驗,所以我不知道它是否已損壞,或者我是否沒有正確配置。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM