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

Boost C++ UDP Socket在Windows下接收133个包后停止的求助

UDP分包传输在Windows客户端接收中断问题

我通过服务器向客户端发送UDP数据包,服务器将数据拆分为500字节的包发送,客户端接收后累加数据并反序列化为对象。目前遇到的问题是:Windows客户端最多接收133个包后就停止接收,仿佛没有更多数据包发到Socket,但服务器实际发送了完整的1238个包;该问题仅在Windows下出现,OSX环境运行完全正常。


服务器发送数据包代码

// sends @buffer of size @length to @endpoint
// @buffer already contains a header, and the method splits @buffer into chunks and send it one by one
void server::send_package(char* buffer, int length, udp::endpoint endpoint){
    if (length > BUFFER){
        protocol::header header;
        int dataLength = length - sizeof (header);

        // copy header from buffer
        memcpy(&header, buffer, sizeof(header));
        header.isEnd = false;

        int position = 0;

        // allocate memory to collect data to send
        char* data_to_send = new char[dataLength];

        // copy data
        memcpy(data_to_send, &buffer[sizeof(header)], dataLength);
        header.totalPackages = dataLength/(BUFFER-sizeof (header));

        // create chucks of data and send
        while (position < dataLength){
            int frame_size = BUFFER;
            header.currentPackage++;
            if (dataLength-position+sizeof (header) <= BUFFER) {
                header.isEnd = true;
                frame_size = dataLength-position+sizeof (header);
            }
            char* temp_buffer = new char[frame_size];
            header.length = frame_size-sizeof(header);

            // set the header of a chunk
            memcpy(temp_buffer, &header, sizeof(header));

            // set data to chunk
            memcpy(&temp_buffer[sizeof (header)], &data_to_send[position], frame_size-sizeof(header));

            // send chunk
            socket->send_to(boost::asio::buffer(temp_buffer, frame_size), endpoint);
            socket->wait(boost::asio::ip::tcp::socket::wait_write);

            position += frame_size-sizeof(header);
        }
    } else {
        socket->async_send_to(boost::asio::buffer(buffer, length), endpoint,
                              boost::bind(&server::release_sent_buffer,
                                          this,
                                          buffer, length)
        );
    }
}

客户端接收数据包代码

void connectionManager::handle_receive( const boost::system::error_code &error,
                                        std::size_t size,
                                        udp::endpoint* ep) {

    if (size > 0) {
       // _lock.try_lock();
        protocol::header header;
        memcpy(&header, &recv_buffer, sizeof(header));
        logg("response from server received " + boost::asio::ip::address_v4(header.ip).to_string());
        logg("received header:");
        logg(protocol::getHeaderInfo(header));
        std::stringstream ss;
        ss << "header.length = " << header.length;
        logg(ss.str().c_str());
        udp::endpoint endpoint(boost::asio::ip::address_v4(header.ip), _server_port);
        switch (header.command) {

             case protocol::commands::server_instance_instruments_state_response: {

                 package_chain chain(size-sizeof(header));
                 memcpy(chain.data, &recv_buffer[sizeof(header)], size-sizeof(header));
                 packages[header.id].push_back(chain);

                 // at Windows machine the last package is #133. But 1248 packages expected.
                 // WHY????...
                 int packs = (packages[header.id].size());

                 if (header.isEnd) {
                     char* buf = getDataFromPackages(header.id, header.length);
                     std::stringstream str;
                     str << buf;

                     boost::archive::text_iarchive ar(str);
                     instance_plugin_information* inst_inf;
                     inst_inf = new instance_plugin_information();
                     try {
                         ar & inst_inf;
                         if (onPluginStateResponse != nullptr) {
                             onPluginStateResponse(*inst_inf);
                         }
                     } catch (const std::exception& e) {
                          
                     }
                 }
                 break;
             }
  }
        // We will hang on this line when package #133 received.
        socket->wait(boost::asio::ip::tcp::socket::wait_read);
        connectionManager::start_receive();
}

问题排查与修复建议

  1. 修正Socket等待类型
    客户端代码中错误使用了boost::asio::ip::tcp::socket::wait_read,但实际是UDP Socket,Windows对这种类型不匹配的兼容性极差,直接导致wait调用卡住。应改为udp::socket::wait_read。

  2. 调大UDP接收缓冲区
    Windows默认UDP接收缓冲区远小于OSX,服务器高速发送时缓冲区很快溢出,后续数据包被直接丢弃。可以手动设置更大的缓冲区:

    boost::asio::socket_base::receive_buffer_size option(10 * 1024 * 1024); // 设置为10MB
    socket->set_option(option);
    
  3. 控制服务器发送速率
    服务器当前无间隔连续发送,Windows网络栈无法处理高密度UDP包。可以在每次send_to后添加微小延时,或改用异步发送配合io_context调度:

    // 替换同步send_to和wait,改用异步发送
    socket->async_send_to(boost::asio::buffer(temp_buffer, frame_size), endpoint,
        [this, temp_buffer](const boost::system::error_code& ec, std::size_t) {
            delete[] temp_buffer; // 发送完成后释放内存
        }
    );
    io_context.run_one(); // 调度异步任务,避免阻塞
    
  4. 修复内存泄漏
    服务器代码中data_to_send和temp_buffer使用new分配后未释放,长期运行会导致内存泄漏,间接影响稳定性。需在循环结束后delete[] data_to_send,异步发送的temp_buffer在回调中释放。

  5. 修正分包计算逻辑
    服务器中header.totalPackages = dataLength/(BUFFER-sizeof (header))未处理余数情况,若dataLength不能被单包数据大小整除,会导致分包数量计算错误。应改为:

    header.totalPackages = (dataLength + (BUFFER - sizeof(header)) - 1) / (BUFFER - sizeof(header));
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 18:00:51