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

news/2025/1/15 15:10:14/

在现代网络中,很多设备都处于 NAT(网络地址转换)或防火墙后面,这使得直接访问这些设备变得困难。在这种情况下,网络穿透技术就显得非常重要。本文将介绍三种常用的网络穿透技术:TCP 打洞、UDP 打洞和 UPnP。
在这里插入图片描述

一、TCP 打洞

1.1 什么是 TCP 打洞?

TCP 打洞(TCP Hole Punching)是一种使 NAT 后的两个客户端通过第三方服务器建立直接连接的方法。NAT 通常会阻止外部主机直接与内部主机通信,因此需要借助外部服务器来协调连接。

1.2 工作原理

  1. 建立与中继服务器的连接:两个 NAT 后的客户端 A 和 B 先分别与公共服务器 S 建立连接。
  2. 交换外部地址:服务器 S 了解 A 和 B 的外部 IP 和端口,并将这些信息发送给彼此。
  3. 尝试直接连接:A 和 B 分别尝试使用彼此的外部 IP 和端口进行连接,如果两端的 NAT 设备允许,则连接成功。

在这里插入图片描述

1.3 示例代码

以下是一个简单的 Python 示例,演示了通过 TCP 打洞进行连接的过程。

import socket# Server listens for incoming connections and exchanges client information
def server():s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.bind(('0.0.0.0', 12345))s.listen(2)print("Server waiting for connections...")conn_a, addr_a = s.accept()print(f"Client A connected: {addr_a}")conn_b, addr_b = s.accept()print(f"Client B connected: {addr_b}")# Exchange addressesconn_a.send(f"{addr_b[0]}:{addr_b[1]}".encode())conn_b.send(f"{addr_a[0]}:{addr_a[1]}".encode())conn_a.close()conn_b.close()s.close()# Clients attempt to connect to each other using exchanged information
def client():s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)s.connect(('server_ip', 12345))  # Replace 'server_ip' with the actual IP of the serverpeer_info = s.recv(1024).decode()peer_ip, peer_port = peer_info.split(':')# Attempt to connect to peertry:peer_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)peer_socket.connect((peer_ip, int(peer_port)))print("Connected to peer!")except Exception as e:print(f"Failed to connect to peer: {e}")s.close()

二、UDP 打洞

2.1 什么是 UDP 打洞?

UDP 打洞(UDP Hole Punching)与 TCP 打洞类似,是一种让处于 NAT 后的两台主机通过第三方服务器建立直接 UDP 连接的技术。与 TCP 不同的是,UDP 是无连接的协议,允许 NAT 主机更容易接受来自外部的连接请求。

2.2 工作原理

  1. 与服务器通信:两台客户端 A 和 B 分别与公共服务器 S 进行通信,服务器记录它们的外部 IP 和端口。
  2. 交换地址:服务器将 A 和 B 的外部 IP 和端口互相传递。
  3. 直接发送 UDP 数据包:A 和 B 尝试通过彼此的外部地址直接发送 UDP 数据包,利用 NAT 会话表进行数据传输。
    在这里插入图片描述

2.3 示例代码

import socket# UDP Server to exchange addresses
def udp_server():s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.bind(('0.0.0.0', 12345))print("Server waiting for messages...")data_a, addr_a = s.recvfrom(1024)print(f"Received from A: {addr_a}")data_b, addr_b = s.recvfrom(1024)print(f"Received from B: {addr_b}")# Exchange addressess.sendto(f"{addr_b[0]}:{addr_b[1]}".encode(), addr_a)s.sendto(f"{addr_a[0]}:{addr_a[1]}".encode(), addr_b)# UDP Client to communicate through hole punching
def udp_client():s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)s.sendto(b'Hello from client', ('server_ip', 12345))  # Replace 'server_ip' with actual server IPpeer_info, _ = s.recvfrom(1024)peer_ip, peer_port = peer_info.decode().split(':')# Send message to peers.sendto(b'Hello peer!', (peer_ip, int(peer_port)))try:response, _ = s.recvfrom(1024)print(f"Received from peer: {response}")except socket.timeout:print("No response from peer")s.close()

三、UPnP(通用即插即用)

3.1 什么是 UPnP?

UPnP(Universal Plug and Play,通用即插即用)是一种网络协议,允许设备自动发现和与网络中的其他设备进行通信。在 NAT 环境下,UPnP 可以自动打开路由器的端口,从而允许外部设备访问位于内网中的设备。

UPnP 主要用于家庭网络和小型局域网,它通过设备的自动配置来简化网络中的设备通信过程。

3.2 工作原理

  1. 设备发现:客户端设备通过发送 SSDP(简单服务发现协议)请求,查找网络中的 UPnP 设备。
  2. 获取路由器的设备描述:通过 SSDP 发现的设备提供一个设备描述 XML 文件,描述其功能和端点。
  3. 请求端口映射:客户端通过向路由器发送请求,要求映射一个外部端口到内网设备的特定端口。
    在这里插入图片描述

3.3 示例代码

可以使用第三方库 miniupnpc 来实现 UPnP 端口映射,以下是一个 Python 示例。

pip install miniupnpc
import miniupnpcdef upnp_port_mapping():upnp = miniupnpc.UPnP()upnp.discoverdelay = 200upnp.discover()  # Discover UPnP devicesupnp.selectigd()  # Select Internet Gateway Deviceexternal_port = 12345internal_port = 54321local_ip = upnp.lanaddr  # Get local IP address# Add port mapping (TCP)upnp.addportmapping(external_port, 'TCP', local_ip, internal_port, 'Test Port Mapping', '')print(f"Port {external_port} mapped to {local_ip}:{internal_port} (TCP)")# Optionally, remove the port mapping# upnp.deleteportmapping(external_port, 'TCP')upnp_port_mapping()

四、总结

  • TCP 打洞:通过第三方服务器交换外部地址,尝试建立直接的 TCP 连接。
  • UDP 打洞:类似 TCP 打洞,但使用 UDP 协议,更容易成功。
  • UPnP:通过自动化的端口映射,使内网设备更易于被外部设备访问。

这三种技术在 P2P 应用中非常重要,特别是在 NAT 或防火墙环境下,它们能够显著提高连接的成功率。


http://www.ppmy.cn/news/1526255.html

相关文章

【Elasticsearch系列五】Java API

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

C++系列-函数对象/仿函数

函数对象/仿函数 💢什么是仿函数💢仿函数的使用💢💢像普通函数一样使用💢💢可以有自己的状态💢💢可以作为函数的参数💢💢可以作为模板参数💢&…

ElementUI 快速入门:使用 Vue 脚手架搭建项目

文章目录 一 . ElementUI 的基本安装1.1 通过 Vue 脚手架创建项目1.2 在 vue 脚手架中安装 ElementUI1.3 编写页面 ElementUI 是 Vue.js 的强大 UI 框架,让前端界面开发变得简单高效。本教程将带你从安装到实战,快速掌握 ElementUI 的核心技巧。 核心内容…

手机玩机常识____展讯芯片刷机平台ResearchDownload的一些基本常识与问题解决

展讯ResearchDownload工具 展讯芯片的刷机工具--ResearchDownload下载工具"是一款专为用户设计的高效、便捷的下载管理软件,它能够帮助用户快速、稳定地从互联网上获取各种文件。这款工具以其强大的功能和良好的用户体验,在众多展讯芯片下载工具中脱…

【大数据方案】智慧大数据平台总体建设方案书(word原件)

第1章 总体说明 1.1 建设背景 1.2 建设目标 1.3 项目建设主要内容 1.4 设计原则 第2章 对项目的理解 2.1 现状分析 2.2 业务需求分析 2.3 功能需求分析 第3章 大数据平台建设方案 3.1 大数据平台总体设计 3.2 大数据平台功能设计 3.3 平台应用 第4章 政策标准保障体系 4.1 政策…

校园水电费管理|基于java的校园水电费管理小程序系统 (源码+数据库+文档)

校园水电费管理 目录 基于java的校园水电费管理小程序系统 一、前言 二、系统设计 三、系统功能设计 小程序端 后台功能模块 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大厂码农|毕…

Spring Boot-API版本控制问题

在现代软件开发中,API(应用程序接口)版本控制是一项至关重要的技术。随着应用的不断迭代,API 的改动不可避免,如何在引入新版本的同时保证向后兼容,避免对现有用户的影响,是每个开发者需要考虑的…

掌握MATLAB中的图形用户界面布局管理器

在MATLAB中,图形用户界面(GUI)的设计对于创建专业且用户友好的应用至关重要。布局管理器在GUI设计中扮演着核心角色,它们负责在窗口中自动管理和调整控件的位置和大小。本文将详细介绍MATLAB中的布局管理器,包括它们的…