You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Boost.Asio创建UDP接收线程时遇无效参数错误求助

问题:Boost ASIO UDP接收线程报错(错误码10022)

问题背景

我在C++中使用Boost ASIO库创建线程监听UDP响应,类中接收线程的代码如下:

tello::tello(boost::asio::io_service& io_service, boost::asio::ip::udp::socket& socket, const boost::asio::ip::udp::endpoint& remote_endpoint)
    : ip(remote_endpoint.address().to_string()),
    port(remote_endpoint.port()),
    io_service(io_service),
    socket(socket),
    remote_endpoint(remote_endpoint)
{

}

void tello::ReceiveThread() {
    while (isListening_) {
        try {
            char receivedData[1024];
            boost::system::error_code error;

            size_t len = socket.receive_from(boost::asio::buffer(receivedData), remote_endpoint, 0, error);

            if (error && error != boost::asio::error::message_size) {
                throw boost::system::system_error(error);
            }

            receivedData[len] = '\0';

            spdlog::info("Received UDP data: {}", receivedData);
        }
        catch (const std::exception& e) {
            std::cerr << "Error receiving UDP data: " << e.what() << std::endl;
        }
    }
}

void tello::StartListening() {
    std::thread udpThread(&tello::ReceiveThread, this);
    udpThread.detach(); // Detach the thread so it runs independently
}

void tello::StopListening() {
    isListening_ = false;
}

main.cpp中的启动代码:

boost::asio::io_service io_service;
boost::asio::ip::udp::socket socket(io_service);
boost::asio::ip::udp::endpoint remote_endpoint(boost::asio::ip::address::from_string("192.168.0.1"), 12345); // Replace with the actual IP address and port
socket.open(boost::asio::ip::udp::v4());

tello drone(io_service, socket, remote_endpoint);
drone.StartListening();

代码编译无错误,但运行时控制台报错:

Error receiving UDP data: An invalid argument was supplied [system:10022 at C:\Users\(username)\boost_1_82_0\boost\asio\detail\win_iocp_socket_service.hpp:418:5 in function 'receive_from']

环境:Windows 64位系统、C++14、Boost 1.82


解决方案

1. 绑定UDP Socket到本地端口

UDP Socket调用open()后必须绑定到本地端口才能接收数据,否则操作系统无法确定监听目标。在main.cpp的socket.open()后添加绑定代码:

// 绑定到任意可用本地端口,也可指定固定端口(如8889)
boost::asio::ip::udp::endpoint local_endpoint(boost::asio::ip::udp::v4(), 0);
socket.bind(local_endpoint);

2. 修正receive_from的端点参数

receive_from的第二个参数是输出参数,用于存储发送方的端点信息,不能直接传入构造时的remote_endpoint(该对象为const引用,且receive_from会修改它)。修改ReceiveThread代码:

void tello::ReceiveThread() {
    while (isListening_) {
        try {
            char receivedData[1024];
            boost::system::error_code error;
            // 创建临时端点对象,用于接收发送方的地址和端口
            boost::asio::ip::udp::endpoint sender_endpoint;

            size_t len = socket.receive_from(boost::asio::buffer(receivedData), sender_endpoint, 0, error);

            if (error && error != boost::asio::error::message_size) {
                throw boost::system::system_error(error);
            }

            receivedData[len] = '\0';

            spdlog::info("Received UDP data from {}:{}: {}", sender_endpoint.address().to_string(), sender_endpoint.port(), receivedData);
        }
        catch (const std::exception& e) {
            std::cerr << "Error receiving UDP data: " << e.what() << std::endl;
        }
    }
}

3. 保证isListening_的线程安全性

isListening_被多个线程读写,必须使用原子类型避免竞态条件。在tello类中修改声明:

#include <atomic>

class tello {
    // ... 其他成员 ...
    std::atomic<bool> isListening_{false};
    // ... 其他成员 ...
};

同时修改启停函数,确保状态切换的原子性:

void tello::StartListening() {
    isListening_ = true;
    std::thread udpThread(&tello::ReceiveThread, this);
    udpThread.detach();
}

void tello::StopListening() {
    isListening_ = false;
    // 关闭socket唤醒阻塞的receive_from调用,避免线程无限等待
    socket.close();
}

4. 阻止主线程提前退出(可选)

如果主线程直接退出,会导致子线程被强制终止。在main函数末尾添加阻塞逻辑:

// 等待用户输入后退出
std::string input;
std::cout << "Press enter to exit..." << std::endl;
std::getline(std::cin, input);

drone.StopListening();

内容的提问来源于stack exchange,提问作者Ethan James

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 16:15:05