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
相关产品推荐
相关产品推荐

