代码之家  ›  专栏  ›  技术社区  ›  Jamboree

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

  •  2
  • Jamboree  · 技术社区  · 8 年前

    我正在尝试在服务器(公共IP上)和客户端(通过NAT)之间使用UDP进行双向通信。我的逻辑是,如果服务器向IP和它接收数据包的端口发送一些数据,客户端仍然应该得到它,因为NAT将具有最终将数据包发送给客户端的映射。

    客户端有两个进程,一个用于发送数据包,另一个用于接收数据。服务器一直在等待数据,如果它获得数据,它会将数据发送回接收数据的端口和IP。

    客户端代码如下:

    客户端接收。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\u发送。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\u send\u 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\u recv)不能工作。既然重复使用了相同的端口,那么client\u recv应该工作正常吗?为什么它会失败,是什么让相同的套接字在客户端上发送和接收工作?

    client\u send\u 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 回复  |  直到 8 年前
        1
  •  2
  •   Steffen Ullrich    8 年前

    TL;TR:问题与NAT无关。而是关于不太具体的vs,。套接字上更具体的绑定。

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

    • 客户端接收。pl绑定到0.0.0.0:
      UDP_IP = '0.0.0.0'#my ip address in the local network
    • client\u发送。pl最初也显式绑定到0.0.0.0:
      sock.bind(('0.0.0.0', 5000))
      但套接字将在内部重新绑定到本地系统的传出IP,以便使用正确的传出IP地址发送数据包:
      sock.sendto(MESSAGE + ' # ' + str(i), (UDP_IP, UDP_PORT))
      请注意,您在netstat中看不到这个新绑定,它似乎在内核中更深入。

    这意味着您将得到两个插座:

    • 客户端接收。pl有一个绑定到0.0.0.0:5000的套接字
    • client\u发送。pl有一个绑定到本地ip的套接字:5000

    如果数据包从服务器到达,它将进入最特定的套接字,即client\u send的套接字。pl.因此,client\u recv。pl从不接收数据包。

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

    推荐文章