使用C语言向pcap文件写入数据时遇Wireshark截断错误求助
问题:PCAP文件在Wireshark中提示“The captured file appears to have been cut short in the middle of the packet”
你希望在循环中把单个float数据写入PCAP文件,使生成的文件中UDP数据包数量与循环次数一致,但用Wireshark打开文件时出现截断错误,代码如下:
const char* filename = "data.pcap"; pcap_t* pcap_handle = pcap_open_dead(DLT_RAW, 65535); pcap_dumper_t* pcap_file_3 = pcap_dump_open(pcap_handle, filename); void saveData(float data, pcap_dumper_t* pcap_file_1) { struct timeval tv; gettimeofday(&tv, NULL); /* packet header */ struct pcap_pkthdr packet_header; packet_header.ts = tv; packet_header.caplen = packet_header.len = sizeof(data) + sizeof(packet_header); pcap_dump((u_char*)pcap_file_1, &packet_header, (const u_char*)&data); } /* for loop which sends the data to the saveData function */ for(size_t i{0U}; i < 300; i++) { CODE TO COMPUTE estimated_val saveData(estimated_val, pcap_file_3); } pcap_dump_close(pcap_file_3); pcap_close(pcap_handle);
错误原因分析
- 数据包长度计算错误:
packet_header.caplen和packet_header.len代表的是数据包内容的实际长度(不包含PCAP文件自身的包头pcap_pkthdr),你错误地将pcap_pkthdr的大小加入其中,导致Wireshark认为每个数据包需要更多字节,但实际只写入了4字节的float数据,因此触发截断提示。 - 链路层类型不匹配:你使用了
DLT_RAW类型,该类型要求数据包必须是完整的IP层数据,但你仅写入了一个float值,并非合法的IP包,Wireshark解析时会判定这是不完整的IP数据包,进而报错。
修复方案
方案1:用自定义链路层类型存储原始float数据
如果仅需存储float数据、不需要Wireshark解析为UDP包,可使用DLT_USER类型,Wireshark会将数据视为自定义负载,不会尝试解析为网络协议:
#include <pcap.h> #include <sys/time.h> const char* filename = "data.pcap"; // 使用DLT_USER作为链路层类型,最大快照长度设为65535 pcap_t* pcap_handle = pcap_open_dead(DLT_USER, 65535); pcap_dumper_t* pcap_file_3 = pcap_dump_open(pcap_handle, filename); void saveData(float data, pcap_dumper_t* pcap_file_1) { struct timeval tv; gettimeofday(&tv, NULL); struct pcap_pkthdr packet_header; packet_header.ts = tv; // 数据包内容长度为float的大小(4字节) packet_header.caplen = packet_header.len = sizeof(float); pcap_dump((u_char*)pcap_file_1, &packet_header, (const u_char*)&data); } int main() { for(size_t i{0U}; i < 300; i++) { float estimated_val = i * 0.1f; // 替换为你的计算逻辑 saveData(estimated_val, pcap_file_3); } pcap_dump_close(pcap_file_3); pcap_close(pcap_handle); return 0; }
方案2:生成合法UDP数据包(让Wireshark正常识别)
如果需要Wireshark显示为标准UDP包,必须构造完整的以太网帧、IP头和UDP头,再附加float数据:
#include <pcap.h> #include <sys/time.h> #include <netinet/ip.h> #include <netinet/udp.h> #include <string.h> #include <arpa/inet.h> // 以太网帧头部 struct eth_header { u_char dst_mac[6]; u_char src_mac[6]; u_short eth_type; }; const char* filename = "data.pcap"; // 使用DLT_EN10MB(以太网)作为链路层类型 pcap_t* pcap_handle = pcap_open_dead(DLT_EN10MB, 65535); pcap_dumper_t* pcap_file_3 = pcap_dump_open(pcap_handle, filename); void saveUdpPacket(float data, pcap_dumper_t* pcap_file_1) { struct timeval tv; gettimeofday(&tv, NULL); // 构造各层头部与负载 struct eth_header eth; struct ip ip_hdr; struct udphdr udp_hdr; char payload[sizeof(float)]; memcpy(payload, &data, sizeof(float)); // 填充以太网头部 memset(eth.dst_mac, 0xff, 6); // 广播MAC地址 memset(eth.src_mac, 0x00, 6); // 示例源MAC地址 eth.eth_type = htons(0x0800); // IP协议类型 // 填充IP头部 ip_hdr.ip_v = 4; ip_hdr.ip_hl = 5; ip_hdr.ip_tos = 0; ip_hdr.ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + sizeof(float)); ip_hdr.ip_id = htons(12345); ip_hdr.ip_off = 0; ip_hdr.ip_ttl = 64; ip_hdr.ip_p = IPPROTO_UDP; ip_hdr.ip_src.s_addr = inet_addr("192.168.1.100"); // 示例源IP ip_hdr.ip_dst.s_addr = inet_addr("192.168.1.200"); // 示例目的IP ip_hdr.ip_sum = 0; // 可由pcap自动计算或手动校验 // 填充UDP头部 udp_hdr.source = htons(1234); // 示例源端口 udp_hdr.dest = htons(5678); // 示例目的端口 udp_hdr.len = htons(sizeof(struct udphdr) + sizeof(float)); udp_hdr.check = 0; // 可选,跳过校验和计算 // 拼接完整数据包 char packet[sizeof(struct eth_header) + sizeof(struct ip) + sizeof(struct udphdr) + sizeof(float)]; int offset = 0; memcpy(packet + offset, ð, sizeof(eth)); offset += sizeof(eth); memcpy(packet + offset, &ip_hdr, sizeof(ip_hdr)); offset += sizeof(ip_hdr); memcpy(packet + offset, &udp_hdr, sizeof(udp_hdr)); offset += sizeof(udp_hdr); memcpy(packet + offset, payload, sizeof(float)); struct pcap_pkthdr packet_header; packet_header.ts = tv; packet_header.caplen = packet_header.len = sizeof(packet); pcap_dump((u_char*)pcap_file_1, &packet_header, (const u_char*)packet); } int main() { for(size_t i{0U}; i < 300; i++) { float estimated_val = i * 0.1f; // 替换为你的计算逻辑 saveUdpPacket(estimated_val, pcap_file_3); } pcap_dump_close(pcap_file_3); pcap_close(pcap_handle); return 0; }
说明
- 方案1适合仅需存储数据、无需协议解析的场景,Wireshark会将数据包识别为“User 0”类型,负载即为你的float数据。
- 方案2会生成标准UDP数据包,Wireshark可正常解析以太网、IP、UDP层信息及负载中的float数据,循环300次将生成300个UDP包。
内容的提问来源于stack exchange,提问作者rkc
相关产品推荐
相关产品推荐

