Windows UDP sockets: recvfrom() fails with error 10054
In Windows, if host A use UDP socket and call sendto()
to send something to host B, but B doesn't bind any port so that B doesn't receive the message, and then host A call recvfrom()
to receive some message, recvfrom()
will failed, and WSAGetLastError()
will return 10054
.
It's a bug of Windows. If UDP socket recv a ICMP(port unreachable) message after send a message, this error will be stored, and next time call recvfrom()
will return this error.
There are 2 ways to solve this problem:
- Make sure host B has already bound the port you want to send to.
- Disable this error by using following code:
#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);
Reference: http://www.cnblogs.com/cnpirate/p/4059137.html
Related videos on Youtube
Heowyn
Updated on September 15, 2022Comments
-
Heowyn over 1 year
Hello everyone.
I'm trying to use Windows sockets to send and receive UDP packets (in C++).
It worked well until three days ago, when the program stopped behaving properly.
To summarize the situation:- When calling WSAPoll() on my socket, it always returns my socket updated with EVERY revents possible (corresponding to every events I gave the pollfd), even if there is no server launched.
- When calling recvfrom() and no server is launched, it returns SOCKET_ERROR with error code 10054(*).
- When calling recvfrom() and a server is launched, it works properly - blocks until it receives something.
- The behavior is the same whether I try to connect to localhost or to a distant host.
(*) I investigated this error. In UDP, it means that there is an ICMP problem. ("On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.").
I indeed call sendto() before recvfrom(), so the problem's not here.
I tried to put down my firewall to see if it changed anything, but it didn't. I also tried to put down every network flowing through my PC. In this state I managed to get the program to work for a few minutes, but when I enabled the networks it stopped working again. I tried to repeat the process but it would not work anymore.
I tried compiling with both visual studio (2015) and MinGW.
I tried on another computer too (under Windows 7, mine has Windows 8.1), to no avail.
Here is a simple test file which does not work on my computer.#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; }
Two questions:
- Why does WSAPoll() always returns an updated socket, even if there wasn't any interaction with it ?
- Why does recvfrom() return this error and how can I fix it ? I suppose it comes from my computer. I tried allowing ICMP through my firewall but it didn't change anything, maybe I did something wrong ?
Edit: I fixed my main program (not shown here because it is way too large) by just ignoring any "error 10054" I received. Now it works the same way it does on Unix.
Still, it is not really a solution (ignoring an error code... meh) and if anyone knows why I get the "ICMP Port Unreachable" error when callingsendto()
, I'd be glad to hear about it. -
Njål Arne Gjermundshaug over 6 yearsThanks for providing the answer. Here's how to do it with a boost socket in case someone else needs to: WSAIoctl(boostSocket.get()->native(), SIO_UDP_CONNRESET, &bNewBehavior, sizeof bNewBehavior, NULL, 0, &dwBytesReturned, NULL, NULL);