I'm trying to have a two way communication using UDP between a server (on public IP) and a client(across a NAT). My logic says that if server sends some data to the IP and the port it received the packet from, the client should still get it, because NAT would have the mapping to send the packet to the client ultimately.
Client has 2 processes, one to send packets, another process to receive the data. Server keeps on waiting for data, and if it gets data, it sends data back to the Port and IP where from the data was received.
Client code below:
client_recv.py
import socket
import sys
UDP_IP = '0.0.0.0'#my ip address in the local network
UDP_PORT = 5000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(1024)
print ("received message:" + data)
client_send.py
import socket
import time
import sys
UDP_IP = 'XXXXXXX.com'#external server IP address
UDP_PORT = 4000
MESSAGE = "Hi!"
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 5000))
i = 0
while True:
sock.sendto(MESSAGE + ' # ' + str(i), (UDP_IP, UDP_PORT))
time.sleep(1)
i = i + 1
The server (on XXXXX.com - public IP) gets the packets, but not the client. Below is the code to receive and send packets on server:
server_send_recv.py
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('0.0.0.0', 4000))
while True:
data, inetaddr = sock.recvfrom(1024)
print('Received ' + data)
(ip, port) = inetaddr
print("IP:"+str(ip)+",Port:"+str(port))
sock.sendto('Hi From Server (against ' + data + ')', (ip, port))
EDIT 1:
As already stated in the answer, the same socket has to be used, so I did the following, and it worked. However, I'm still not clear why a different socket (client_recv), which was bound to the same Port on client would not work. Since the same ports are being reused, the client_recv should have worked right? Why did it fail, and what made the same socket to send and receive on client work?
client_send_recv.py
import socket
import time
import sys
UDP_IP = 'twig-me.com'#external server IP address
UDP_PORT = 4000
MESSAGE = "Hi!"
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.bind(('0.0.0.0', 5000))
i = 0
while True:
print ("Sending message:" + str(i))
sock.sendto(MESSAGE + ' # ' + str(i), (UDP_IP, UDP_PORT))
time.sleep(1)
i = i + 1
data, addr = sock.recvfrom(1024)
print ("received message:" + data)
TL;TR: the problem is unrelated to NAT. It is instead about less specific vs,. more specific bindings on sockets.
You have two clients on the same system:
UDP_IP = '0.0.0.0'#my ip address in the local network
sock.bind(('0.0.0.0', 5000))
But the socket will be internally re-bound to the outgoing IP of your local system in order to send the packet with the correct outgoing IP address::
sock.sendto(MESSAGE + ' # ' + str(i), (UDP_IP, UDP_PORT))
Note that you cannot see this new binding in netstat, it seems to be deeper in the kernel.
This means you end up with two sockets:
If a packet arrives from the server it goes to the most specific socket, i.e. the one from client_send.pl. Thus client_recv.pl never receives the packet.
If you instead change the IP address in client_recv.pl to the IP of your local system you get two sockets, both bound to
your-local-ip:5000
. Since there is no most specific socket in this case the packet is actually delivered to the first one which reads it, in your caseclient_recv.pl
.