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

WinDivert批量模式仅捕获单个数据包问题求助

问题:WinDivert批量捕获仅能获取单个数据包

我尝试用WinDivert实现批量捕获并回注数据包,期望一次捕获10或20个包以适配高速网络,但实际每次只能捕获单个数据包,效果和使用WinDivertRecv/WinDivertSend一致。以下是我的代码:

#include <windivert.h>
#include <conio.h>
#include <iostream>
#include <windows.h>
#include <chrono>
#include <thread>
#include <queue>
#include <mutex>

using namespace std;

#define MAX_BATCH 20        // Number of packets to capture per batch
#define MAX_PACKET_SIZE 1500
UINT recvCount = 0;

UINT8 packets[20 * MAX_PACKET_SIZE];        // Space for up to 20 packets
WINDIVERT_ADDRESS addr[20];     // Addresses for up to 20 packets
UINT addr_len = sizeof(addr);

int main()
{
        HANDLE handle = WinDivertOpen("inbound and !loopback", WINDIVERT_LAYER_NETWORK, 0, 0);
        if (handle == INVALID_HANDLE_VALUE) {
            std::cerr << "Failed to open WinDivert handle!\n";
            return 1;
        }
        else
        {
            std::cout << "WinDivert handle Opened Successfully!\n";
        }

        system("pause");

        while (true)
        {
            if (!WinDivertRecvEx(handle, packets, sizeof(packets), NULL, 0, addr, &addr_len, NULL))
            {
                std::cout << "[Error : Packet Reception failed]" << '\n';
            }
            else
            {
                UINT num_packets = addr_len / sizeof(WINDIVERT_ADDRESS);

                std::cout << "[Packet Reception Complete] : " << num_packets <<" , "<< addr << '\n';
            }

            if (!WinDivertSendEx(handle, packets, sizeof(packets), NULL, 0, addr, addr_len, NULL))
            {
                // Handle send error
                std::cout << "[Error : Packet Re-injection failed]" << '\n';
            }
            else
            {
                std::cout << "[Packet Re-injection Complete]" << '\n';
            }

        }

        WinDivertClose(handle);
}

问题原因与修复方案

1. 缺少批量捕获的核心配置

WinDivertRecvEx默认无超时机制,有数据包就立即返回,因此通常只能拿到1个包。需要通过WINDIVERT_RECV_PARAMS结构体指定期望的批量包数量,并设置超时时间,让函数等待凑够指定数量后再返回。

2. 发送时缓冲区长度参数错误

WinDivertSendEx需要传入实际捕获到的数据包总字节数,而非整个缓冲区的sizeof(packets),否则会发送无效的空数据。

修复后的代码

#include <windivert.h>
#include <conio.h>
#include <iostream>
#include <windows.h>

using namespace std;

#define MAX_BATCH 20
#define MAX_PACKET_SIZE 1500

UINT8 packets[MAX_BATCH * MAX_PACKET_SIZE];
WINDIVERT_ADDRESS addr[MAX_BATCH];

int main()
{
    HANDLE handle = WinDivertOpen("inbound and !loopback", WINDIVERT_LAYER_NETWORK, 0, 0);
    if (handle == INVALID_HANDLE_VALUE) {
        cerr << "Failed to open WinDivert handle!\n";
        return 1;
    }
    cout << "WinDivert handle Opened Successfully!\n";

    system("pause");

    while (true)
    {
        UINT recv_len = 0;
        UINT addr_len = sizeof(addr);
        WINDIVERT_RECV_PARAMS recv_params = {0};
        recv_params.NumPackets = MAX_BATCH; // 指定一次捕获的最大包数
        recv_params.Timeout = 10; // 超时时间(毫秒),可根据网络带宽调整

        if (!WinDivertRecvEx(handle, packets, sizeof(packets), &recv_len, 0, addr, &addr_len, &recv_params))
        {
            cout << "[Error : Packet Reception failed]" << '\n';
            continue;
        }

        UINT num_packets = addr_len / sizeof(WINDIVERT_ADDRESS);
        cout << "[Packet Reception Complete] : " << num_packets << " packets\n";

        // 发送时传入实际捕获的字节数recv_len,避免无效数据
        if (!WinDivertSendEx(handle, packets, recv_len, NULL, 0, addr, addr_len, NULL))
        {
            cout << "[Error : Packet Re-injection failed]" << '\n';
        }
        else
        {
            cout << "[Packet Re-injection Complete] : " << num_packets << " packets\n";
        }
    }

    WinDivertClose(handle);
    return 0;
}

关键说明

  • recv_params.NumPackets:设置一次捕获的最大包数,WinDivert会尽可能凑够该数量后返回。
  • recv_params.Timeout:设置等待超时,即使未凑够指定数量,超时后也会返回已捕获的包,避免无限等待。
  • recv_len:记录实际捕获的总字节数,发送时必须传入该值,确保只发送有效数据包。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 10:53:16