网络穿透:TCP 打洞、UDP 打洞与 UPnP

[复制链接]
发表于 2026-1-22 19:24:14 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在当代网络中,许多装备都处于 NAT(网络地点转换)或防火墙背面,这使得直接访问这些装备变得困难。在这种情况下,网络穿透技能就显得非常告急。本文将先容三种常用的网络穿透技能:TCP 打洞、UDP 打洞和 UPnP。

一、TCP 打洞

1.1 什么是 TCP 打洞?

TCP 打洞(TCP Hole Punching)是一种使 NAT 后的两个客户端通过第三方服务器创建直接毗连的方法。NAT 通常会制止外部主机直接与内部主机通讯,因此必要借助外部服务器来调和毗连。
1.2 工作原理


  • 创建与中继服务器的毗连:两个 NAT 后的客户端 A 和 B 先分别与公共服务器 S 创建毗连。
  • 交换外部地点:服务器 S 相识 A 和 B 的外部 IP 和端口,并将这些信息发送给相互。
  • 实行直接毗连:A 和 B 分别实利用用相互的外部 IP 和端口举行毗连,假如两头的 NAT 装备允许,则毗连乐成。

1.3 示例代码

以下是一个简朴的 Python 示例,演示了通过 TCP 打洞举行毗连的过程。
  1. import socket
  2. # Server listens for incoming connections and exchanges client information
  3. def server():
  4.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  5.     s.bind(('0.0.0.0', 12345))
  6.     s.listen(2)
  7.    
  8.     print("Server waiting for connections...")
  9.     conn_a, addr_a = s.accept()
  10.     print(f"Client A connected: {addr_a}")
  11.    
  12.     conn_b, addr_b = s.accept()
  13.     print(f"Client B connected: {addr_b}")
  14.    
  15.     # Exchange addresses
  16.     conn_a.send(f"{addr_b[0]}:{addr_b[1]}".encode())
  17.     conn_b.send(f"{addr_a[0]}:{addr_a[1]}".encode())
  18.    
  19.     conn_a.close()
  20.     conn_b.close()
  21.     s.close()
  22. # Clients attempt to connect to each other using exchanged information
  23. def client():
  24.     s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  25.     s.connect(('server_ip', 12345))  # Replace 'server_ip' with the actual IP of the server
  26.    
  27.     peer_info = s.recv(1024).decode()
  28.     peer_ip, peer_port = peer_info.split(':')
  29.    
  30.     # Attempt to connect to peer
  31.     try:
  32.         peer_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  33.         peer_socket.connect((peer_ip, int(peer_port)))
  34.         print("Connected to peer!")
  35.     except Exception as e:
  36.         print(f"Failed to connect to peer: {e}")
  37.    
  38.     s.close()
复制代码
二、UDP 打洞

2.1 什么是 UDP 打洞?

UDP 打洞(UDP Hole Punching)与 TCP 打洞类似,是一种让处于 NAT 后的两台主机通过第三方服务器创建直接 UDP 毗连的技能。与 TCP 差别的是,UDP 是无毗连的协议,允许 NAT 主机更容易担当来自外部的毗连哀求。
2.2 工作原理


  • 与服务器通讯:两台客户端 A 和 B 分别与公共服务器 S 举行通讯,服务器记录它们的外部 IP 和端口。
  • 交换地点:服务器将 A 和 B 的外部 IP 和端口相互转达。
  • 直接发送 UDP 数据包:A 和 B 实行通过相互的外部地点直接发送 UDP 数据包,使用 NAT 会话表举行数据传输。

2.3 示例代码
  1. import socket
  2. # UDP Server to exchange addresses
  3. def udp_server():
  4.     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  5.     s.bind(('0.0.0.0', 12345))
  6.    
  7.     print("Server waiting for messages...")
  8.     data_a, addr_a = s.recvfrom(1024)
  9.     print(f"Received from A: {addr_a}")
  10.    
  11.     data_b, addr_b = s.recvfrom(1024)
  12.     print(f"Received from B: {addr_b}")
  13.    
  14.     # Exchange addresses
  15.     s.sendto(f"{addr_b[0]}:{addr_b[1]}".encode(), addr_a)
  16.     s.sendto(f"{addr_a[0]}:{addr_a[1]}".encode(), addr_b)
  17. # UDP Client to communicate through hole punching
  18. def udp_client():
  19.     s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  20.     s.sendto(b'Hello from client', ('server_ip', 12345))  # Replace 'server_ip' with actual server IP
  21.    
  22.     peer_info, _ = s.recvfrom(1024)
  23.     peer_ip, peer_port = peer_info.decode().split(':')
  24.    
  25.     # Send message to peer
  26.     s.sendto(b'Hello peer!', (peer_ip, int(peer_port)))
  27.    
  28.     try:
  29.         response, _ = s.recvfrom(1024)
  30.         print(f"Received from peer: {response}")
  31.     except socket.timeout:
  32.         print("No response from peer")
  33.    
  34.     s.close()
复制代码
三、UPnP(通用即插即用)

3.1 什么是 UPnP?

UPnP(Universal Plug and Play,通用即插即用)是一种网络协议,允许装备主动发现和与网络中的其他装备举行通讯。在 NAT 情况下,UPnP 可以主动打开路由器的端口,从而允许外部装备访问位于内网中的装备。
UPnP 重要用于家庭网络和小型局域网,它通过装备的主动设置来简化网络中的装备通讯过程。
3.2 工作原理


  • 装备发现:客户端装备通过发送 SSDP(简朴服务发现协议)哀求,查找网络中的 UPnP 装备。
  • 获取路由器的装备形貌:通过 SSDP 发现的装备提供一个装备形貌 XML 文件,形貌其功能和端点。
  • 哀求端口映射:客户端通过向路由器发送哀求,要求映射一个外部端口到内网装备的特定端口。

3.3 示例代码

可以使用第三方库 miniupnpc 来实现 UPnP 端口映射,以下是一个 Python 示例。
  1. pip install miniupnpc
复制代码
  1. import miniupnpc
  2. def upnp_port_mapping():
  3.     upnp = miniupnpc.UPnP()
  4.     upnp.discoverdelay = 200
  5.     upnp.discover()  # Discover UPnP devices
  6.     upnp.selectigd()  # Select Internet Gateway Device
  7.    
  8.     external_port = 12345
  9.     internal_port = 54321
  10.     local_ip = upnp.lanaddr  # Get local IP address
  11.    
  12.     # Add port mapping (TCP)
  13.     upnp.addportmapping(external_port, 'TCP', local_ip, internal_port, 'Test Port Mapping', '')
  14.    
  15.     print(f"Port {external_port} mapped to {local_ip}:{internal_port} (TCP)")
  16.    
  17.     # Optionally, remove the port mapping
  18.     # upnp.deleteportmapping(external_port, 'TCP')
  19.    
  20. upnp_port_mapping()
复制代码
四、总结


  • TCP 打洞:通过第三方服务器交换外部地点,实行创建直接的 TCP 毗连。
  • UDP 打洞:类似 TCP 打洞,但使用 UDP 协议,更容易乐成。
  • UPnP:通过主动化的端口映射,使内网装备更易于被外部装备访问。
这三种技能在 P2P 应用中非常告急,特殊是在 NAT 或防火墙情况下,它们可以大概明显进步毗连的乐成率。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表