我正在尝试在服务器(在公共IP上)和客户端(跨NAT)之间使用UDP进行双向通信。我的逻辑说,如果服务器将某些数据发送到IP和从其接收数据包的端口,则客户端仍应获取数据,因为NAT最终将映射发送给客户端。

客户端有2个进程,一个进程发送数据包,另一个进程接收数据。服务器一直在等待数据,如果获取数据,它将数据发送回端口和IP,从那里接收数据。

客户端代码如下:

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


服务器(在XXXXX.com-公共IP上)获取数据包,但不获取客户端。以下是在服务器上接收和发送数据包的代码:

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))


编辑1:

正如答案中已经提到的,必须使用相同的套接字,所以我做了以下工作,它起作用了。但是,我仍然不清楚为什么绑定到客户端上相同端口的其他套接字(client_recv)无法正常工作。由于相同的端口正在重用,所以client_recv应该工作正常吗?为什么会失败,是什么使相同的套接字在客户端上进行发送和接收?

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:该问题与NAT无关。相反,它是相对不那么具体的。套接字上的更具体的绑定。

您在同一系统上有两个客户端:


client_recv.pl绑定到0.0.0.0:
UDP_IP = '0.0.0.0'#my ip address in the local network
最初也将client_send.pl明确绑定到0.0.0.0:
sock.bind(('0.0.0.0', 5000))
但是,套接字将在内部重新绑定到本地系统的传出IP,以便使用正确的传出IP地址发送数据包:
sock.sendto(MESSAGE + ' # ' + str(i), (UDP_IP, UDP_PORT))
请注意,您无法在netstat中看到此新绑定,它似乎在内核中更深。


这意味着您将获得两个套接字:


client_recv.pl具有绑定到0.0.0.0:5000的套接字
client_send.pl具有绑定到your-local-ip:5000的套接字


如果数据包从服务器到达,它将到达最特定的套接字,即来自client_send.pl的套接字。因此,client_recv.pl从不接收该数据包。

如果改为将client_recv.pl中的IP地址更改为本地系统的IP,则会得到两个套接字,两个套接字均绑定到your-local-ip:5000。由于在这种情况下没有最具体的套接字,因此实际上将数据包传递到读取它的第一个套接字,在您的情况下为client_recv.pl

07-24 13:59
查看更多