I have been trying to get a udp client/server working so I can implement it in an Unreal Engine 5 project, but while I have no trouble connecting from my windows machine to my ubuntu server I cannot send traffic in the other direction.
I currently have a C++ program I developed from this tutorial https://www.youtube.com/watch?v=uIanSvWou1M that sends udp packets to my ubuntu server via port 53003. This works perfectly. My ubuntu server is simply running a nodejs script that listens on port 53003 and then replies to the ip address attached to the incoming udp message via port 53004
I have a second cpp program running on my windows machine that is listening on port 53004. Here’s the code:
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
void main()
{
// Startup Winsock
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
if(wsOk != 0)
{
cout << "Can't start Winsock" << wsOk;
}
// Bind socket to ip address and port
SOCKET in = socket(AF_INET, SOCK_DGRAM, 0);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = ADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(53004); // Convert from little to big endian
if (bind(in, (sockaddr*)&serverHint, sizeof(serverHint)) == SOCKET_ERROR)
{
cout << "Can't bind socket! " << serverHint.sin_port << endl;
return;
}
sockaddr_in client;
int clientLength = sizeof(client);
ZeroMemory(&client, sizeof(client));
char buf[1024];
// Enter a loop
while (true)
{
ZeroMemory(buf, 1024);
// Wait for message
int bytesIn = recvfrom(in, buf, 1024, 0, (sockaddr*)&client, &clientLength);
if (bytesIn == SOCKET_ERROR)
{
cout << "Error receiving from client " << WSAGetLastError() << endl;
continue;
}
// Display message and client info
char clientIp[256];
ZeroMemory(clientIp, 256);
// make client info printable (number to pointer to string
inet_ntop(AF_INET, &client.sin_addr, clientIp, 256);
cout << "Message received from " << clientIp << " : " << buf << endl;
}
// close socket
closesocket(in);
// shutdown winsock
WSACleanup();
}
I can alter my first program to send to ip address 127.0.0.1 on port 53004 and the above code receives/prints it with no problem. However when I try to send to it by my public ip address (instead of 127.0.0.1) it does not work.
Obviously my ubuntu program also cannot successfully send to the above program. Even using a netcat command like this does not work (my.ip.add.num is my public ip address)
echo 'test' | netcat -u my.ip.add.num 53004
I initially tried creating an inbound rule in windows firewall for port 53004 and when that didn’t work I tried just completely turning windows firewall off. Yet still nothing works.
If anyone has any suggestions I would be extremely grateful!
2
Answers
I figured out my problem - Thanks to @ewong and @JesperJuhl I investigated my wifi router and the NAT settings were blocking all udp ports. I did not realize this until I did a little more research on how routers work, but apparently your public ip is actually just to your router. So if you google "what's my ip" you're getting your router's ip address and not your actual windows machine.
In reality your router passes traffic along to several connected internal ip addresses. So for instance your computer might be 192.168.1.1 and your phone might be 192.168.1.2. If you try to connect to your windows machine (as I did) from a linux server via your public ip you're just going to reach your router, and it won't know which internal ip address to send the udp packet to (so it won't send anything).
To fix this I applied port forwarding to my router settings for port 53004 (basically I created a rule in my netgear router's dashboard that says if there is any traffic to the routers public ip address on port 53004 forward it to the internal ip that my computer is on, e.g. 192.168.1.1) and that solved my problem! My application now receives messages from my ubuntu server.
However this is not a good long term solution. Instead I'll need to be a little more sophisticated from a networking side. I'll either need to investigate if I can both send and receive reliably on one port like 53003 OR I'll need to connect to the server on port 53003, have the server respond with a new port connect to, and then have my client connect to that second port to then receive data from.
The main trick with UDP connections through NAT is that once your computer connects outbound to ip address and port, only then will your router allow traffic in the opposite direction without port forwarding. Hope that helps the next person who runs into this issue.
A UDP server receives a packet with ‘IP + port’ address from the client, use this final address to send data back to the client, the client in turn receives it through the connection already established via the final address of the server that duly opened a port UDP, remembering that connection via UDP protocol has no guarantee of order or successful delivery of packets, not even a descending confirmation of a signed connection.