WinSocket UDP仅在Wireshark启动时正常,求排查FPGA通信问题
问题背景
我有一台FPGA设备,监听1000端口的UDP报文FFFF,收到后会回复同样的UDPFFFF。在Code::Blocks中编写的C项目已添加链接器选项-lwsock32,但当前代码仅在Wireshark启动时能正常工作:此时FPGA的JTAG可收到FFFF报文,通信正常;关闭Wireshark后,JTAG仅能看到ARP报文(设备已回复),无后续UDP通信。
设备信息
- FPGA:MAC地址
34:34:45:79:34:54,IP地址192.168.150.111 - PC:同网段IP
192.168.150.5
问题现象
启动Wireshark后,可看到FPGA回复ARP报文,UDP通信完全正常;关闭Wireshark后,仅能捕获到ARP请求与回复,UDP报文无法正常传输。

现有代码
#include <stdio.h> #include <stdbool.h> #include <windows.h> #include <conio.h> int main(int argc, char* argv[]) { SOCKET sckt; struct sockaddr_in sckt_addr; DWORD timeout; WSADATA WSAData; int rc = WSAStartup(0x202, &WSAData); if(rc != 0) { printf("Windows Sockets初始化失败"); return -1; } sckt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(sckt == INVALID_SOCKET) { printf("Windows Sockets初始化失败"); return -1; } sckt_addr.sin_family = AF_INET; sckt_addr.sin_addr.s_addr = INADDR_ANY; sckt_addr.sin_port = htons(1000); if(bind(sckt, (LPSOCKADDR)&sckt_addr, sizeof(sckt_addr)) == SOCKET_ERROR) { printf("Windows Sockets初始化错误"); closesocket(sckt); return -1; } sckt_addr.sin_addr.s_addr = inet_addr("192.168.150.111"); char o_data[2]; o_data[0] = o_data[1] = 0xFF; const int i_data_len = 7; char i_data[7]; int sckt_addr_size = 32; while(true) { rc = sendto(sckt, o_data, 2, 0, (SOCKADDR *)&sckt_addr, sizeof(sckt_addr)); if (rc != 2) { printf("Socket错误"); return 1; } rc = recvfrom(sckt, i_data, i_data_len, 0, (SOCKADDR *)&sckt_addr, &sckt_addr_size); if (WSAGetLastError() == WSAETIMEDOUT) { printf("未收到FPGA响应"); continue; } else { if (((unsigned char)i_data[0] << 8) + (unsigned char)i_data[1] == 0xFFFF) printf("\n\n设备回复了FFFF\n"); else { printf("\n\n收到错误响应。"); return 2; } } } closesocket(sckt); WSACleanup(); return 0; }
问题原因分析与解决建议
核心原因
关闭Wireshark后UDP无法通信,本质是PC的ARP缓存未正确更新FPGA的MAC地址,或者发送UDP时未触发ARP请求的完整处理流程。Wireshark启动时会开启网络混杂模式,强制刷新数据包捕获逻辑,间接触发了ARP缓存更新或数据包的正常转发。
针对性解决方法
方法一:添加静态ARP条目
以管理员权限打开Windows命令提示符,执行以下命令绑定FPGA的IP与MAC地址,避免动态ARP缓存失效:arp -s 192.168.150.111 34-34-45-79-34-54方法二:完善Socket超时设置
现有代码未设置接收超时,且sendto后直接进入recvfrom可能导致ARP请求未完成就开始等待响应。在Socket初始化后添加超时配置:timeout = 1000; // 设置1秒接收超时 setsockopt(sckt, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));方法三:修正Socket地址逻辑
现有代码中绑定本地端口后直接修改了同一个地址结构体,可能导致地址信息混乱。建议创建独立的目标地址结构体:struct sockaddr_in dest_addr; memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.sin_family = AF_INET; dest_addr.sin_addr.s_addr = inet_addr("192.168.150.111"); dest_addr.sin_port = htons(1000);后续sendto操作使用这个独立的
dest_addr结构体。方法四:检查防火墙规则
确保Windows防火墙未拦截1000端口的UDP报文,可临时关闭防火墙测试,或在防火墙设置中添加UDP 1000端口的双向允许规则。
内容的提问来源于stack exchange,提问作者user13313191

