UDP 客户端跨 NAT 无法从服务器接收数据 [英] UDP client across NAT could not receive data from server

查看:52
本文介绍了UDP 客户端跨 NAT 无法从服务器接收数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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.

客户端有2个进程,一个发送数据包,另一个接收数据.服务器一直在等待数据,如果获取到数据,则将数据发送回接收数据的端口和 IP.

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_recv.py

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

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)获取数据包,而不是客户端.下面是在服务器上接收和发送数据包的代码:

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

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 应该可以正常工作吗?为什么它失败了,是什么让在客户端上发送和接收相同的套接字工作?

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

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 无关.相反,它是关于不太具体的与,.套接字上更具体的绑定.

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:

  • client_recv.pl 绑定到 0.0.0.0:
    UDP_IP = '0.0.0.0'#我在本地网络的ip地址
  • 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 中看到这个新绑定,它似乎在内核中更深.

这意味着你最终会得到两个套接字:

This means you end up with two sockets:

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

如果数据包从服务器到达,它会转到最具体的套接字,即来自 client_send.pl 的套接字.因此 client_recv.pl 永远不会收到数据包.

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.

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

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 case client_recv.pl.

这篇关于UDP 客户端跨 NAT 无法从服务器接收数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆