首页 文章

跨NAT的UDP客户端无法从服务器接收数据

提问于
浏览
2

我正在尝试在服务器(在公共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))

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

1 回答

  • 2

    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 .

相关问题