I am working on a solution based on a local network with a “server” that needs to manage several “players”. My protocol of choice is UDP, because it is easy, I do not need connections, my traffic consists of short commands from time to time, and I want to use a combination of broadcast messages for synchronization and single target messages for individual player commands.
Multicast TCP would be an alternative, but more complex, not quite suitable for the task, and often not supported by the hardware.
Unfortunately, I have a strange problem:
The first datagram that is sent to a specific ip using sendto is lost. Any datagram sent a short time after that to the same ip is received. But if I wait a while (a few minutes), the first "sendto" will be lost again.
Broadcast datagrams always work. Local sendings (to the same computer) always work.
I assume that the operating system or router / switch has some translation table from IP to MAC addresses, which are forgotten when they are not used for several minutes, and that, unfortunately, leads to the loss of datagrams. I could observe this behavior with other equipment of the router / switch, so my suspect is a Windows network layer.
I know that UDP is by definition “unreliable,” but I can't believe it is so far that even if the physical connection works and everything is well-defined, packets can get lost. Then it will be literally useless.
Technically, I open the UDP socket, bind it to the port and INADRR_ANY. Then I use "sendto" and "recvfrom". I never connect - I do not want, because I have several players. As far as I know, UDP should work without a connection.
My current workaround is that I regularly send fictitious datagrams to all specific ips players - this solves the problem, but it’s somehow “unsatisfactory”
Question: Does anyone know this problem? Where is it from? How can I solve it?
Edit:
I threw it back to the following test program:
int _tmain(int argc, _TCHAR* argv[]) { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET Sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); SOCKADDR_IN Local = {0}; Local.sin_family = AF_INET; Local.sin_addr.S_un.S_addr = htonl(INADDR_ANY); Local.sin_port = htons(1234); bind(Sock, (SOCKADDR*)&Local, sizeof(Local)); printf("Press any key to send...\n"); int Ret, i = 0; char Buf[4096]; SOCKADDR_IN Remote = {0}; Remote.sin_family = AF_INET; Remote.sin_addr.S_un.S_addr = inet_addr("192.168.1.12"); // Replace this with a valid LAN IP which is not the hosts one Remote.sin_port = htons(1235); while(true) { _getch(); sprintf(Buf, "ping %d", ++i); printf("Multiple sending \"%s\"\n", Buf); // Ret = connect(Sock, (SOCKADDR*)&Remote, sizeof(Remote)); // if (Ret == SOCKET_ERROR) printf("Connect Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); Ret = sendto(Sock, Buf, strlen(Buf), 0, (SOCKADDR*)&Remote, sizeof(Remote)); if (Ret != strlen(Buf)) printf("Send Error!\n", Buf); } return 0;
The program opens the UDP Socket and sends 3 datagrams per line for each keystroke to a specific IP address. Start the proxy server, watching your UDP traffic, press the key, wait a while and press the key again. You do not need a receiver at the remote IP address, it does not matter, except that you do not receive black marked "inaccessible" packets. This is what you get:

As you can see, the first dispatch initiated an ARP lookup for the IP address. While this search was waiting, the first 2 of three consecutive shipments were lost. The second keystroke (after completing the IP search) sent 3 messages correctly. Now you can retry sending messages and it will work until you wait (in about a minute, until the transfer of the addressee is lost again), and you will see the drop-out again.
This means: when sending UDP messages, there is no send buffer and ARP requests are expected! All messages are lost except the last. Also, "sendto" is not blocked until it is successfully delivered, and there is no error return!
Well, it surprises me and makes me a little sad, because it means I need to live with my current workaround or implement an ACK system that sends only one message and then waits for an answer - which will not be easier and mean a lot difficulties.