一段时间以来,我的UDP打孔系统出现了严重问题,这可能涉及到我现在无法触及的事情 . 我会尽可能准确地解释,因为这真的困扰着我:
UDP Hole打孔方法涉及第三个主机S,它基本上是公共的(不在任何类型的NAT或持久防火墙之后),将由两个客户端A和B使用以相互了解 . 客户端A向S发送udp数据包,以便S可以知道其公共IP和端口(由A的NAT映射) . 客户B也这样做 . 然后S通过发送到A B的公共地址和A的公共地址来匹配A和B.因此,他们每个人都知道彼此的地址并且可以进行通信 .
到目前为止一切都很好,但这里有一个问题:它仅适用于特殊情况 .
我知道对称NAT(NAT将您的私有IP和端口映射到您想要到达的每个目标地址的特定不同地址的问题),所以假设我发送一个数据包到S1和S2,S1会看到一个公共地址为50263,而S2为50264 . 我也知道一些非对称NAT要求您在允许从同一地址接收UDP数据包之前将UDP数据包发送到特定地址 .
所以我到目前为止所理解的是,只要你的NAT不是Symmetric,当打开一个新套接字,并发送任何字节数组时,你的NAT将为它分配一个公共IP和端口 . 公共服务器告诉您的对等方这个公共地址,以便它可以与您通信 . 然后,您必须向该对等方发送数据包以允许他回复 .
但它实际上并不是每次都有效 . 我已经在我的大学公寓里尝试过,并设法使用我的公共IP地址连接到自己,即使是在NAT后面 . 我还设法向朋友发送UDP数据包,但它在我做的一百次测试中只工作了一次 . 我现在正在家里尝试它根本不起作用 .
我在互联网上设置了2个公共VPS,并向每个人发送了一个数据包,看看我的NAT是否是Symmetric,但不是,两个端口显示的端口是相同的 . 我只能从那些公共服务器上找到自己 . 使用Wireshark,我观察到数据包离开了我的计算机,但似乎它们被丢弃了 .
我编写了简单的python脚本来尝试简单地发送给自己:
Server
import socket
import sys
from helper import *
# This script is used to allow a client to know which external address it has.
def main():
# Port used to receive client requests
port = 6666
# We create a UDP socket on this port
sockfd = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sockfd.bind (("", port))
print ("Address discoverer started on port %d" % port)
# Server loop
while True:
# We wait for any client to request for his address.
data, addr = sockfd.recvfrom(1)
# Once a client has sent a request, we send him back his external address, which we obtained using the packet he sent us.
sockfd.sendto (addr2bytes(addr), addr)
print ("Client %s:%d requested his address" % addr)
if __name__ == "__main__":
main()
Client
import sys
import socket
from helper import *
def main():
master = ("xxx.xxx.xxx.xxx", 6666)
me = ("yyy.yyy.yyy.yyy", 6666)
sockfd = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)
sockfd.bind(('',6666))
sockfd.sendto (bytearray([0]), master)
data, addr = sockfd.recvfrom (6)
a = bytes2addr(data)
print ('My address is %s:%d' % a)
for i in range (0, 10):
sockfd.sendto ('hi myself'.encode('utf-8'), me)
data, addr = sockfd.recvfrom (1024)
print ("Received : " + data.decode('utf-8'))
if __name__ == "__main__":
main()
在我的一个公共VPS上执行,它的工作原理 . 在家里执行,我什么都没收到 . 似乎从公共主机发送授予所有访问权限,但NAT背后的完全不同 .
我错过了什么基本的东西?我想我做了很多可能的测试,但没有成功 .
1 回答
根据您要实现的目标,您可能希望使用IGD(spec)来检索您的公共IP和/或自动配置端口转发 . 据我所知,大多数家用路由器都支持UPnP IGD .
这是一个示例脚本,它使用miniupnpc,一个最小的UPnP IGD客户端,以及来自python标准库的ipaddress和socket模块:
样本输出: