Windows UDP套接字:recvfrom()失败,错误10054

大家好。
我试图使用Windows套接字发送和接收UDP数据包(在C ++中)。
它运行良好,直到三天前,程序停止正常运行。
总结情况:

  • 当在我的套接字上调用WSAPoll()时,即使没有启动服务器,它也会始终返回我的套接字(更新了每个可能的向导)(对应于我给予pollfd的每个事件)。
  • 当调用recvfrom()并且没有服务器启动时,它返回错误代码10054(*)的SOCKET_ERROR。
  • 当调用recvfrom()并启动一个服务器时,它正常工作 – 阻塞,直到它收到一些东西。
  • 无论我尝试连接到本地主机还是远程主机,行为都是一样的。

(*)我调查了这个错误。 在UDP中,这意味着有一个ICMP问题。 (“在UDP数据报套接字上,这个错误指示先前的发送操作导致ICMP端口不可达消息”)。
我确实在recvfrom()之前调用sendto(),所以问题不在这里。
我试图放下防火墙,看它是否改变了什么,但是没有改变。 我也试图放下通过我的个人电脑stream通的每一个networking。 在这种状态下,我设法让程序工作了几分钟,但是当我启用networking时,它又停止了工作。 我试图重复这个过程,但现在不行了。
我试着编译与Visual Studio(2015)和MinGW。
我也试过另一台电脑(在Windows 7下,我的Windows 8.1),无济于事。

这是一个简单的testing文件,不能在我的电脑上运行。

#undef _WIN32_WINNT #define _WIN32_WINNT 0x501 #include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <vector> #include <iostream> int main() { int clientSock; char buf[100]; int serverPort; /* Initializing WSA */ WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); /* I create my socket */ struct addrinfo specs; struct addrinfo *addr = new addrinfo; ZeroMemory(&specs, sizeof(specs)); specs.ai_family = AF_INET; specs.ai_socktype = SOCK_DGRAM; specs.ai_flags = 0; getaddrinfo("127.0.0.1", "2324", &specs, &addr); clientSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); /* I get the server's address */ struct sockaddr_in serverAddr; serverAddr.sin_family = AF_INET; serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); serverAddr.sin_port = htons(2324); int len = sizeof(struct sockaddr); /* I'll poll & recvfrom on my socket */ std::vector<pollfd> fds; pollfd fd; fd.fd = clientSock; fd.events = POLLRDNORM; fd.revents = -1; fds.push_back(fd); while(1) { memset(buf,0,sizeof(buf)); printf("\nClient--->: "); gets(buf); /* It's UDP, so it doesn't matter if there is someone to receive the packet */ sendto(clientSock, buf, strlen(buf), 0, (sockaddr*)&serverAddr ,len); memset(buf,0,sizeof(buf)); int ret; /* Always returns "1" */ if ((ret = WSAPoll(fds.data(), 1, 0)) > 0) { std::cout << ret; /* Always returns "-1" */ std::cout << recvfrom(clientSock,buf,sizeof(buf),0, (sockaddr*)&serverAddr,&len) << std::endl; printf("\n--->From the server: "); printf("%s",buf); } } closesocket(clientSock); WSACleanup(); return 0; } 

两个问题:

  1. 为什么WSAPoll()总是返回一个更新的套接字,即使它没有任何交互?
  2. 为什么recvfrom()返回这个错误,我该如何解决? 我想它来自我的电脑。 我试过通过我的防火墙允许ICMP,但它没有改变任何东西,也许我做错了什么?

编辑:我修正了我的主程序(这里没有显示,因为它太大了),只是忽略了我收到的任何“错误10054”。 现在它和Unix上的方式一样。
不过,这不是一个真正的解决scheme(忽略错误代码… meh),如果有人知道为什么我调用sendto()时得到“ICMP Port Unreachable”错误,我很高兴听到这个消息。

在Windows中,如果主机A使用UDP套接字并且调用sendto()向主机B发送一些东西,但是B不绑定任何端口以使得B不接收消息,然后主机A调用recvfrom()来接收一些消息, recvfrom()将失败, WSAGetLastError()将返回10054

这是Windows的一个bug。 如果UDP套接字在发送消息后收到ICMP(端口不可达)消息,则将存储该错误,并且下一次调用recvfrom()将返回此错误。

有两种方法可以解决这个问题:

  1. 确保主机B已经绑定了您要发送到的端口。
  2. 使用以下代码禁用此错误:
 #include <Winsock2.h> #include <Mstcpip.h> #include <stdio.h> #pragma comment(lib, "ws2_32.lib") #define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR, 12) BOOL bNewBehavior = FALSE; DWORD dwBytesReturned = 0; WSAIoctl(iSock, SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL); 

参考: http : //www.cnblogs.com/cnpirate/p/4059137.html