- 浏览: 2196992 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (1240)
- mac/IOS (287)
- flutter (1)
- J2EE (115)
- android基础知识 (582)
- android中级知识 (55)
- android组件(Widget)开发 (18)
- android 错误 (21)
- javascript (18)
- linux (70)
- 树莓派 (18)
- gwt/gxt (1)
- 工具(IDE)/包(jar) (18)
- web前端 (17)
- java 算法 (8)
- 其它 (5)
- chrome (7)
- 数据库 (8)
- 经济/金融 (0)
- english (2)
- HTML5 (7)
- 网络安全 (14)
- 设计欣赏/设计窗 (8)
- 汇编/C (8)
- 工具类 (4)
- 游戏 (5)
- 开发频道 (5)
- Android OpenGL (1)
- 科学 (4)
- 运维 (0)
- 好东西 (6)
- 美食 (1)
最新评论
-
liangzai_cool:
请教一下,文中,shell、C、Python三种方式控制led ...
树莓派 - MAX7219 -
jiazimo:
...
Kafka源码分析-序列5 -Producer -RecordAccumulator队列分析 -
hp321:
Windows该命令是不是需要安装什么软件才可以?我试过不行( ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
hp321:
Chenzh_758 写道其实直接用一下代码就可以解决了:JP ...
ImageIO读jpg的时候出现javax.imageio.IIOException: Unsupported Image Type -
huanghonhpeng:
大哥你真强什么都会,研究研究。。。。小弟在这里学到了很多知识。 ...
android 浏览器
因为当前 IPV4地址的缺乏 ,nat、防火墙的中介设备和不对称寻址建立起来的 p2p通信机制造成了地址访问的问题。
在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够直接通信。可是随着节点的增多, ip地址使用紧张,他们需要中介设备如 nat连在一起。
私有网络中的节点可以直接连接到相同私有网络中的其他节点,也可以连接到全局地址空间中拥有全球唯一 ip地址的节点。。然而 nat通常只允许临时的向外连接申请,对于向内的申请会拒绝。这就造成了在 natA内网中的节点 A连接 natB内网中的节点 B时连接申请报到 natB时就被阻止了。此时我们需要的就是穿越技术。。。
总体来说穿越技术是利用一个公共服务器中转,使节点 A、 B都连接到中转服务器 S之后,通过 S中转 A发送到 B的数据报或者是中转连接申请,,使 A、 B对于 natA和 natB来说都是向外申请。。。
1、 中转数据报: A、 B都先向外与服务器 S建立接连,然后通过 S中转 A、 B之间的数据报。。
2、 反向连接:当 A、 B都与 S建立了连接,并且只有一个节点在 nat之后(假设 A在 natA之后)。。当 B向 A申请连接时,申请背 natA拒绝。 B可以向 S提出申请要与 A建立连接,然后 S向 A发出指令,通知 A主动向 B申请建立连接。。
【 UDP打洞】
1、 A、 B在同一个 nat之后:
用户 A让 S做介绍人来与 B建立对话
(1) A向 S发送一个消息请求与 B建立连接
(2) S使用 B的公共终端( 155.99.25.11: 62005)和私有终端( 10.1.1.3)响应 A
(3) 同时 S也想 B发送 A的公共终端( 155.99.25.11: 62000)和私有终端( 10.0.0.1),但是发送到公共终端的消息不一定能达到 B取决于 NAT是否支持“发夹”转化(回环转化)
(4) 如果 nat支持发夹转化的话,应用程序就可以免除私有和共有终端都要试图连接的复杂性。。
2、不同 NAT后面的节点
(1) 注册, A、 B都想服务器 S注册 natA安排了 62000端口用作 A和 S对话使用, natB安排了 31000端口用作 B和 S对话使用, A向 S的注册消息中报告了自己的私有终端 10.0.0.1: 4321这种情况下 A的公共终端是 155.99.25.11: 62000,同理 B的私有终端 10.1.1.3: 4321和公共终端 136.76.29.7: 31000
(2) A发送请求消息到 S,请求与 B建立连接,作为响应 S向 A发送了 B的私有终端和公共终端也向 B发送了 A的私有和公共终端。
(3) 既然 A、 B处在不同的子网中,那么 A、 B的私有终端是不能公共路由的,发送的消息肯能会发到自己子网中的 ip中(应为不同子网中的私有 ip可以相同)
(4) 当从 A发向 B的第一个消息到达 natA时, natA注意到这是一个新的外出会话, natA看到源地址是子网中地址,而目的地址是外网地址,所以 natA将从私有终端 10.0.0.1: 4321的外出会话转化到对应公共终端 155.99.25.11: 62000,这样 A的第一个到 B的公共终端的外出会话消息就在 natA上“打了一个洞”。新的 UDP会话由 A的私有网络上的终端 10.0.0.1: 4321/138.76.29.7: 31000和 internet上的公共终端 155.99.25.11: 62000/138.76.29.7:31000标识,同理 B也建立了对 A的私有、公共连接标识。
(5) 如果 A发向 B的公共终端的消息在 B发向 A的第一个消息穿过 B自己的 natB之前到达了 natB的话, natB会认为 A的内入消息是禁止的,丢弃 B的请求消息,但是 B的请求消息在 natB上为 A打了一洞,此时洞双向打开,通信可以进行下去了。。。
3、多级 NAT后面的节点:
( 1) A、 B都建立与 S的向外连接
( 2)最终连接目的:
Aà B 10.0.0.1à 10.0.1.2:55000
Bà A 10.0.0.3à 10.0.1.1:45000
( 3)但是在此时 A、 B无法知道伪公众终端 10.0.1.2:55000和 10.0.1.1:45000。 S只看到了 155.99.25.11: 32000和 155.99.25.11: 62005。
( 4)此时相应的 A、 B也只知道 155.99.25.11: 32000和 155.99.25.11: 62005
( 5)只能依赖 natC的发夹转化。
当 A-à B,即 10.0.0.1—>155.99.25.11: 62005时 natA将数据报中源地址 10.0.0.1转化为 10.0.1.1然后发送到 natC,当 natC发现目的地址 ip是 155.99.25.11是自己转化过的 ip后, natC就会转化数据报中的源地址和目的地址,再发送到私有网络中。 155.99.25.11: 62000--à 10.0.1.2: 55000
( 6)当数据报到 B私有网络时,同样方法进行转化。。
UDPServer.java:
UDPClientA.java:
UDPClientB.java
在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够直接通信。可是随着节点的增多, ip地址使用紧张,他们需要中介设备如 nat连在一起。
私有网络中的节点可以直接连接到相同私有网络中的其他节点,也可以连接到全局地址空间中拥有全球唯一 ip地址的节点。。然而 nat通常只允许临时的向外连接申请,对于向内的申请会拒绝。这就造成了在 natA内网中的节点 A连接 natB内网中的节点 B时连接申请报到 natB时就被阻止了。此时我们需要的就是穿越技术。。。
总体来说穿越技术是利用一个公共服务器中转,使节点 A、 B都连接到中转服务器 S之后,通过 S中转 A发送到 B的数据报或者是中转连接申请,,使 A、 B对于 natA和 natB来说都是向外申请。。。
1、 中转数据报: A、 B都先向外与服务器 S建立接连,然后通过 S中转 A、 B之间的数据报。。
2、 反向连接:当 A、 B都与 S建立了连接,并且只有一个节点在 nat之后(假设 A在 natA之后)。。当 B向 A申请连接时,申请背 natA拒绝。 B可以向 S提出申请要与 A建立连接,然后 S向 A发出指令,通知 A主动向 B申请建立连接。。
【 UDP打洞】
1、 A、 B在同一个 nat之后:
用户 A让 S做介绍人来与 B建立对话
(1) A向 S发送一个消息请求与 B建立连接
(2) S使用 B的公共终端( 155.99.25.11: 62005)和私有终端( 10.1.1.3)响应 A
(3) 同时 S也想 B发送 A的公共终端( 155.99.25.11: 62000)和私有终端( 10.0.0.1),但是发送到公共终端的消息不一定能达到 B取决于 NAT是否支持“发夹”转化(回环转化)
(4) 如果 nat支持发夹转化的话,应用程序就可以免除私有和共有终端都要试图连接的复杂性。。
2、不同 NAT后面的节点
(1) 注册, A、 B都想服务器 S注册 natA安排了 62000端口用作 A和 S对话使用, natB安排了 31000端口用作 B和 S对话使用, A向 S的注册消息中报告了自己的私有终端 10.0.0.1: 4321这种情况下 A的公共终端是 155.99.25.11: 62000,同理 B的私有终端 10.1.1.3: 4321和公共终端 136.76.29.7: 31000
(2) A发送请求消息到 S,请求与 B建立连接,作为响应 S向 A发送了 B的私有终端和公共终端也向 B发送了 A的私有和公共终端。
(3) 既然 A、 B处在不同的子网中,那么 A、 B的私有终端是不能公共路由的,发送的消息肯能会发到自己子网中的 ip中(应为不同子网中的私有 ip可以相同)
(4) 当从 A发向 B的第一个消息到达 natA时, natA注意到这是一个新的外出会话, natA看到源地址是子网中地址,而目的地址是外网地址,所以 natA将从私有终端 10.0.0.1: 4321的外出会话转化到对应公共终端 155.99.25.11: 62000,这样 A的第一个到 B的公共终端的外出会话消息就在 natA上“打了一个洞”。新的 UDP会话由 A的私有网络上的终端 10.0.0.1: 4321/138.76.29.7: 31000和 internet上的公共终端 155.99.25.11: 62000/138.76.29.7:31000标识,同理 B也建立了对 A的私有、公共连接标识。
(5) 如果 A发向 B的公共终端的消息在 B发向 A的第一个消息穿过 B自己的 natB之前到达了 natB的话, natB会认为 A的内入消息是禁止的,丢弃 B的请求消息,但是 B的请求消息在 natB上为 A打了一洞,此时洞双向打开,通信可以进行下去了。。。
3、多级 NAT后面的节点:
( 1) A、 B都建立与 S的向外连接
( 2)最终连接目的:
Aà B 10.0.0.1à 10.0.1.2:55000
Bà A 10.0.0.3à 10.0.1.1:45000
( 3)但是在此时 A、 B无法知道伪公众终端 10.0.1.2:55000和 10.0.1.1:45000。 S只看到了 155.99.25.11: 32000和 155.99.25.11: 62005。
( 4)此时相应的 A、 B也只知道 155.99.25.11: 32000和 155.99.25.11: 62005
( 5)只能依赖 natC的发夹转化。
当 A-à B,即 10.0.0.1—>155.99.25.11: 62005时 natA将数据报中源地址 10.0.0.1转化为 10.0.1.1然后发送到 natC,当 natC发现目的地址 ip是 155.99.25.11是自己转化过的 ip后, natC就会转化数据报中的源地址和目的地址,再发送到私有网络中。 155.99.25.11: 62000--à 10.0.1.2: 55000
( 6)当数据报到 B私有网络时,同样方法进行转化。。
UDPServer.java:
package org.iaiai.test; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; /** * * <br/> * Title: UDPServer.java<br/> * E-Mail: 176291935@qq.com<br/> * QQ: 176291935<br/> * Http: iaiai.iteye.com<br/> * Create time: 2013-1-29 上午11:11:56<br/> * <br/> * @author 丸子 * @version 0.0.1 */ public class UDPServer { public static void main(String[] args) { try { DatagramSocket server = new DatagramSocket(2008); byte[] buf = new byte[1024]; DatagramPacket packet = new DatagramPacket(buf, buf.length); String sendMessage132 = ""; String sendMessage129 = ""; int port132 = 0; int port129 = 0; InetAddress address132 = null; InetAddress address129 = null; for (;;) { server.receive(packet); String receiveMessage = new String(packet.getData(), 0, packet.getLength()); System.out.println(receiveMessage); //接收到clientA if (receiveMessage.contains("132")) { port132 = packet.getPort(); address132 = packet.getAddress(); sendMessage132 = "host:" + address132.getHostAddress() + ",port:" + port132; } //接收到clientB if (receiveMessage.contains("129")) { port129 = packet.getPort(); address129 = packet.getAddress(); sendMessage129 = "host:" + address129.getHostAddress() + ",port:" + port129; } //两个都接收到后分别A、B址地交换互发 if (!sendMessage132.equals("") && !sendMessage129.equals("")) { send132(sendMessage129, port132, address132, server); send129(sendMessage132, port129, address129, server); sendMessage132 = ""; sendMessage129 = ""; } } } catch (Exception e) { e.printStackTrace(); } } private static void send129(String sendMessage132, int port132, InetAddress address132, DatagramSocket server) { try { byte[] sendBuf = sendMessage132.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address132, port132); server.send(sendPacket); System.out.println("消息发送成功!"); } catch (Exception e) { e.printStackTrace(); } } private static void send132(String sendMessage129, int port129, InetAddress address129, DatagramSocket server) { try { byte[] sendBuf = sendMessage129.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address129, port129); server.send(sendPacket); System.out.println("消息发送成功!"); } catch (Exception e) { e.printStackTrace(); } } }
UDPClientA.java:
package org.iaiai.test; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; /** * * <br/> * Title: UDPClientA.java<br/> * E-Mail: 176291935@qq.com<br/> * QQ: 176291935<br/> * Http: iaiai.iteye.com<br/> * Create time: 2013-1-29 上午11:11:56<br/> * <br/> * @author 丸子 * @version 0.0.1 */ public class UDPClientA { public static void main(String[] args) { try { // 向server发起请求 SocketAddress target = new InetSocketAddress("10.1.11.137", 2008); DatagramSocket client = new DatagramSocket(); String message = "I am UPDClinetA 192.168.85.132"; byte[] sendbuf = message.getBytes(); DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target); client.send(pack); // 接收请求的回复,可能不是server回复的,有可能来自UPDClientB的请求内 receive(client); } catch (Exception e) { e.printStackTrace(); } } //接收请求内容 private static void receive(DatagramSocket client) { try { for (;;) { byte[] buf = new byte[1024]; DatagramPacket packet = new DatagramPacket(buf, buf.length); client.receive(packet); String receiveMessage = new String(packet.getData(), 0, packet.getLength()); System.out.println(receiveMessage); int port = packet.getPort(); InetAddress address = packet.getAddress(); String reportMessage = "tks"; //获取接收到请问内容后并取到地址与端口,然后用获取到地址与端口回复内容 sendMessaage(reportMessage, port, address, client); } } catch (Exception e) { e.printStackTrace(); } } //回复内容 private static void sendMessaage(String reportMessage, int port, InetAddress address, DatagramSocket client) { try { byte[] sendBuf = reportMessage.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address, port); client.send(sendPacket); System.out.println("消息发送成功!"); } catch (Exception e) { e.printStackTrace(); } } }
UDPClientB.java
package org.iaiai.test; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.SocketAddress; /** * * <br/> * Title: UDPClientB.java<br/> * E-Mail: 176291935@qq.com<br/> * QQ: 176291935<br/> * Http: iaiai.iteye.com<br/> * Create time: 2013-1-29 上午11:11:56<br/> * <br/> * @author 丸子 * @version 0.0.1 */ public class UDPClientB { public static void main(String[] args) { try { //向server发起请求 SocketAddress target = new InetSocketAddress("10.1.11.137", 2008); DatagramSocket client = new DatagramSocket(); String message = "I am UDPClientB 192.168.85.129"; byte[] sendbuf = message.getBytes(); DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target); client.send(pack); //接收server的回复内容 byte[] buf = new byte[1024]; DatagramPacket recpack = new DatagramPacket(buf, buf.length); client.receive(recpack); //处理server回复的内容,然后向内容中的地址与端口发起请求(打洞) String receiveMessage = new String(recpack.getData(), 0, recpack.getLength()); String[] params = receiveMessage.split(","); String host = params[0].substring(5); String port = params[1].substring(5); System.out.println(host + ":" + port); sendMessage(host, port, client); } catch (Exception e) { e.printStackTrace(); } } //向UPDClientA发起请求(在NAT上打孔) private static void sendMessage(String host, String port, DatagramSocket client) { try { SocketAddress target = new InetSocketAddress(host, Integer.parseInt(port)); for (;;) { String message = "I am master 192.168.85.129 count test"; byte[] sendbuf = message.getBytes(); DatagramPacket pack = new DatagramPacket(sendbuf, sendbuf.length, target); client.send(pack); //接收UDPClientA回复的内容 receive(client); } } catch (Exception e) { e.printStackTrace(); } } //收到UDPClientA的回复内容,穿透已完成 private static void receive(DatagramSocket client) { try { for (;;) { //将接收到的内容打印 byte[] buf = new byte[1024]; DatagramPacket recpack = new DatagramPacket(buf, buf.length); client.receive(recpack); String receiveMessage = new String(recpack.getData(), 0, recpack.getLength()); System.out.println(receiveMessage); //记得重新收地址与端口,然后在以新地址发送内容到UPDClientA,就这样互发就可以了。 int port = recpack.getPort(); InetAddress address = recpack.getAddress(); String reportMessage = "I am master 192.168.85.129 count test"; //发送消息 sendMessage(reportMessage, port, address, client); } } catch (Exception e) { e.printStackTrace(); } } private static void sendMessage(String reportMessage, int port, InetAddress address, DatagramSocket client) { try { byte[] sendBuf = reportMessage.getBytes(); DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length, address, port); client.send(sendPacket); System.out.println("send success"); } catch (Exception e) { e.printStackTrace(); } } }
发表评论
-
小程序textarea完美填坑
2020-07-07 16:09 521相信做微信小程序的码友们都被textarea这个原生组件坑过 ... -
Nginx+Https自己敲命令生成证书
2020-05-18 09:35 947一、准备 环境:centos6.8 ... -
https证书生成环境搭建配置(基于Tomcat和Nginx)
2020-04-24 11:06 821一、基于Tomcat、JDK内置密钥工具: 1、生成服务端证 ... -
史上最强Tomcat8性能优化
2019-11-01 21:41 885授人以鱼不如授人以渔 ... -
SpringBoot配置HTTPS,并实现HTTP访问自动转HTTPS访问
2019-10-07 09:13 5611.使用jdk自带的 keytools 创建证书 打开cmd ... -
Spring Boot工程集成全局唯一ID生成器 UidGenerator
2019-09-16 09:04 856概述 流水号生成器(全局唯一 ID生成器)是服务化系统的基础 ... -
CentOS7下Redis的安装与使用
2019-08-17 11:45 606一、手动安装过程 1、准备工作(安装gcc依赖) yum ... -
Nginx与tomcat组合的简单使用
2019-08-17 10:05 430配置tomcat跳转 请求http出现400的时候在这里配置 ... -
linux下lvs+keepalived安装配置
2019-07-10 14:20 463keepalived主机:192.168.174. ... -
使用Docker搭建Tomcat运行环境
2019-02-08 21:32 4881 准备宿主系统 准备一 ... -
Netty笔记-GlobalEventExecutor
2019-02-06 23:00 6371.概念 /** * Single-thread si ... -
Netty4转发服务的实现方案
2019-02-06 15:03 1135如果用Netty做转发服务(不需要同步应答),Netty中有一 ... -
java手机号归属地查询
2018-12-25 17:16 746所需的包:carrier-1.75.jar 、geocoder ... -
基于Netty4的HttpServer和HttpClient的简单实现
2018-10-17 20:02 691Http 消息格式: Http request: Met ... -
javafx : 支持使用微调(spinner)控制的数字的文本框(NemberTextField)
2018-10-16 00:00 1093最近花了一些时间学习javaFX, 要更深入地理解新GUI包, ... -
我的Java(定制你的Java/JavaFX Runtime)
2018-10-12 23:29 678最新的JDK 11发布了,撒花 新版本的JDK终于有了ope ... -
javaFX的几个新特性,让swing彻底过时
2018-10-12 22:42 667首先声明,Java的GUI曾经 ... -
mac os系统用install4j把jar包生成app
2018-10-05 23:02 1428install4j有windows版也有mac版 mac电脑 ... -
JavaFX Alert对话框
2018-10-05 22:01 23661. 标准对话框 消息对话框 Alert alert = ... -
IDEA Properties中文unicode转码问题
2017-02-17 19:54 1034摘要: 如何让IDEA的properties中的中文进行uni ...
相关推荐
总结,通过Java实现的UDP打洞技术,可以克服NAT的障碍,实现子网间的P2P通信。这在分布式系统、在线游戏、文件共享等领域都有广泛应用。在实际开发中,还需要考虑兼容性、安全性以及网络环境的复杂性。
因为当前 IPV4地址的缺乏 ,nat、防火墙的中介设备和不对称寻址建立起来的 p2p通信机制造成了地址访问的问题。 在 internet最初体系结构中,每个节点都有全球唯一的 ip地址,能够直接通信。可是随着节点的增多, ip...
UDP打洞技术是一种在P2P网络中实现端到端通信的方法,特别是在存在网络地址转换(NAT)的环境中。NAT使得私有网络内的设备无法直接与其他网络的设备通信,因为它们都共享一个公共IP地址。UDP打洞通过利用NAT的某些...
【标题】"java编的P2P程序+源码.rar" 涉及的主要知识点是Java编程语言在实现P2P(对等网络)程序上的应用,以及如何通过UDP打洞技术穿越NAT(网络地址转换)进行通信。P2P网络是一种分布式网络架构,其中每个节点...
总之,通过Netty和UDP协议实现的网络打洞实例,不仅展示了Netty的强大功能,还揭示了网络通信中解决NAT障碍的策略和技术。开发者可以利用这些知识,构建出高效、可靠的P2P应用,如在线游戏、音视频通话等。
P2P打洞技术,也称为UDP打洞或STUN(Session Traversal Utilities for NAT),是为了让两个处于NAT后的设备能够发现彼此并建立直接连接的一种方法。 在P2P UDP打洞过程中,主要涉及以下几个关键知识点: 1. **NAT...
java-udp-qq聊天源码,p2p通信完全实现 UDP打洞实现了子网间的穿透功能,首先在一台拥有公网IP服务器上运行server,在不同的两个子网PC上运行client,输入服务器IP,即可进行打洞,实现不同子网的通信。
UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络内的主机之间直接通信的方法。在互联网上,许多设备由于连接到ISP时采用了NAT,它们的公网IP实际上是路由器分配的内部IP,因此不能直接与其他网络的...
在提供的压缩包中,"P2P之UDP穿透NAT的原理与实现源代码"很可能是用某种编程语言(如C++、Python或Java)实现的示例代码,包含具体的打洞算法和信令交互逻辑。通过阅读和理解这些代码,可以更深入地了解UDP穿透NAT的...
"打洞"(Punching Hole)是P2P网络中的一种技术,用于解决NAT(Network Address Translation)设备导致的通信问题。NAT设备通常会隐藏内部网络中的设备,使得外部网络无法直接与其通信。UDP打洞通过两个位于NAT后的...
STUN (Session Traversal Utilities for NAT) 协议是一种用于网络地址转换(NAT)穿越的技术,它允许位于NAT后的设备发现其公网IP和端口,从而在P2P应用中建立直接通信。Java实现的STUN客户端库,如stun4j,对于...
P2P(对等网络)技术通常会用到UDP打洞,因为它允许对等节点直接通信,减少中心服务器的压力,提高网络效率。在实际应用中,比如在线游戏、视频通话、文件分享等场景,都需要使用UDP打洞技术来实现穿越NAT的高效通信...
UDP打洞技术是一种在内网环境下实现外网访问内网服务的方法,主要应用于P2P通信、游戏联机等场景。UDP(User Datagram Protocol)是一种无连接的、不可靠的传输层协议,它以较小的开销提供了快速的数据传输。在内网...
5. 根据NAT类型,客户端可以采取不同的策略来实现P2P通信,比如使用UDP打洞或者通过TURN服务器转发。 在开发P2P应用时,NAT探测和STUN协议是必不可少的组成部分,它们使得内部网络的设备能够有效地与其他网络节点...
2. **ICE(Interactive Connectivity Establishment)**:ICE是一种更全面的方法,结合了UDP打洞和STUN(Session Traversal Utilities for NAT)服务器。STUN服务器用于获取内置于NAT中的设备的公网映射地址。ICE...
打洞成功"是指在P2P网络中实现NAT穿透(NAT Traversal),以便两个位于内网的节点可以直接通信。在NAT环境下,每个设备都有一个公共IP地址和私有IP地址,多线程在这里的作用是协助进行端口映射和通信测试,确保...
- 打洞和TURN中继模块:根据NAT类型,尝试打洞或使用TURN服务器进行通信。 通过分析和理解这个源代码,我们可以深入学习P2P通信和UDP穿越NAT的实践,这对于开发分布式系统、游戏网络、实时通信应用等领域具有很高的...
QQ通过UDP打洞(UDP Hole Punching)或STUN(Simple Traversal of UDP through NATs)服务器协助,实现内网用户的端口映射,让两个内网用户能直接通信。 2. **分布式哈希表(DHT)**:QQ可能利用DHT技术来存储和...
它涉及到了网络通信中的端口映射、UDP打洞等技术。在这个实验中,需要三台电脑,其中两台被配置为模拟不同的NAT环境,另一台则作为服务器或者客户端,以便测试NAT穿越的实现效果。此外,还需要两台路由器进行配合,...
3. UDP打洞:NAT穿透的关键在于创建两个位于不同NAT之后的设备之间的直接UDP连接。JSTUN会尝试通过发送数据包来在NAT上“打洞”,创建持久的UDP通道。 4. 代理服务器:在某些情况下,可能需要借助STUN服务器或TURN...