目标
路由穿透,实现广域网P2P通讯。
4种典型NAT类型
按照NAT设备在进行地址映射时行为的不同,NAT可以分为以下四种:
-
Full Cone
-
Restricted Cone
-
Port Restricted Cone
-
Symmentric
如何判断本机NAT类型
可以通过PyStun来判断:
- NAT Type: Full Cone
- External IP: 180.160.213.93
- External Port: 32130
几种现代穿透协议
STUN
STUN协议为终端提供一种方式能够获知自己经过NAT映射后的地址,从而替代位于应用层中的私网地址,达到NAT穿透的目的。STUN协议是典型的Client-Server协议,各种具体应用通过嵌入STUN客户端与STUN Server端通讯来完成交互。
在典型的运用STUN进行NAT穿透的场景中,STUN客户端首先向位于公网上的STUN服务器 发送Binding Request消息,STUN服务器接收到请求消息后识别出经过NAT转换后的公网地址60.1.1.1:12345,将其附加在Binding Response消息中返回给客户端。客户端得到这个地址 后用它替换SDP中的私网地址与终端B完成媒体协商。使用STUN进行NAT穿透对应用的要 求是必须使用同样的端口与STUN服务器交互和进行应用层通讯,比如当希望使用端口 37000进行RTP包的NAT穿透时,必须同样使用37000端口与STUN服务器通讯,否则从STUN服务器获得的NAT映射后的地址一般与实际地址时不一样的。另一个要求是STUN客户端与 服务器端的通讯和应用使用获得的NAT映射地址进行应用层通讯在时间上必须有连贯性, 这源于NAT设备建立的绑定有生存时间,当原绑定消亡后,NAT设备为同一个私网地址建 立的新绑定往往不同,因此转换后的公网地址是不同的。
STUN方案的特性如下表:
特性 |
说明 |
实现复杂度 |
实现简单 |
TCP穿透支持 |
不支持 |
对现有设备的要求 |
要求客户端支持,对现有NAT设备无改动要求,需增加STUN服务器 |
可扩展性 |
可扩展性好,与具体协议无关 |
安全性 |
一般 |
健壮性 |
差,不支持symmentric型NAT |
其他 |
支持自动检测NAT类型,使用户即使在使用STUN协议无法实现NAT 穿透时还可以根据NAT类型自主选择其他可使用的NAT穿透方案 |
TURN
TURN解决NAT穿透的思路与STUN类似,都是通过修改应用层中的私网地址达到NAT穿透。 与STUN不同的是,TURN是通过两方通讯的“中间人”的方式实现穿透,在这种方式下, 要进行通讯的两方分别与位于公网上的TURN服务器建立各自的连接进行通讯,由服务器负 责在两方之间进行数据转发。要达到这个目的,实现TURN客户端的终端必须在通讯开始前 与TURN服务器进行交互,得到服务器为其临时分配的位于TURN服务器上的公网地址,客户端使用它替换位于应用层中的私网地址。
TURN方案的特性如下表:
特性 |
说明 |
实现复杂度 |
难于实现。TURN的安全性设计增加终端设置的复杂度 |
TCP穿透支持 |
支持 |
对现有设备的要求 |
对现有NAT设备无要求,要求客户端支持,需增加TURN服务器s |
可扩展性 |
可扩展性好,与具体协议无关 |
安全性 |
一般 |
健壮性 |
好,支持所有类型的NAT |
其他 |
与P2P穿透方式相比,性能时relay穿透方式的弱点。另外TURN无法 实现负载分担,解决的方式是把media relay服务器的分配工作放在 SIP proxy完成 |
ICE
与STUN和TURN相比,ICE并非是解决NAT穿透问题的协议,而是一个框架,在这个框架中, 可以整合其他现存的NAT穿透协议,如STUN、TURN、RSIP等。区别于其他的NAT穿透解 决方案,ICE是一种探索和更新式的解决方案,通过搜集自身和对端尽可能多的网络信息(各种网络地址),尝试在这些地址间建立数据通道,并在这一过程中不断更新先前收集到的信息,从而找出和选择能够进行NAT穿透的数据通道。
ICE方案的特性如下表:
特性 |
说明 |
实现复杂度 |
一般 |
TCP穿透支持 |
支持 |
对现有设备的要求 |
对NAT设备无要求,支持所有类型的NAT设备。客户端必须支持, 网路结构中需增加STUN/TURN服务器 |
可扩展性 |
可扩展性好,与具体协议无关 |
安全性 |
较好 |
健壮性 |
好,适用与所有NAT及NAT拓扑类型,且由于存在中继服务器,NAT 穿透一般总是能成功 |
其他 |
试验环境
两台PC——
A位于公网IP为180.160.213.93 的路由下,内网IP为192.168.1.100,通过端口8888通讯。
B位于公网IP为180.160.233.193的路由下,内网IP为192.168.1.107,通过端口6666通讯。
大致如图所示:
STUN服务器采用免费的公用STUN服务器,具体STUN服务器列表在此。
试验过程
基于开源的Java ICE库ice4j,编写客户端,其中,客户端调用代码:
- package com.hankcs.network;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.SocketAddress;
- public class Peer
- {
- public static void main(String[] args) throws Throwable
- {
- try
- {
- IceClient client = new IceClient(8888, "text");
- client.init();
- client.exchangeSdpWithPeer();
- client.startConnect();
- final DatagramSocket socket = client.getDatagramSocket();
- final SocketAddress remoteAddress = client
- .getRemotePeerSocketAddress();
- System.out.println(socket.toString());
- new Thread(new Runnable()
- {
- public void run()
- {
- while (true)
- {
- try
- {
- byte[] buf = new byte[1024];
- DatagramPacket packet = new DatagramPacket(buf,
- buf.length);
- socket.receive(packet);
- System.out.println(packet.getAddress() + ":" + packet.getPort() + " says: " + new String(packet.getData(), 0, packet.getLength()));
- }
- catch (IOException e)
- {
- e.printStackTrace();
- }
- }
- }
- }).start();
- new Thread(new Runnable()
- {
- public void run()
- {
- try
- {
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
- String line;
- // 从键盘读取
- while ((line = reader.readLine()) != null)
- {
- line = line.trim();
- if (line.length() == 0)
- {
- break;
- }
- byte[] buf = (line).getBytes();
- DatagramPacket packet = new DatagramPacket(buf, buf.length);
- packet.setSocketAddress(remoteAddress);
- socket.send(packet);
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }).start();
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
- }
为了简便,没有引入SIP服务器,直接用人工复制粘贴的方式交换了两台设备的SDP信息,其中
A的SDP信息:
- v=0
- o=ice4j.org 0 0 IN IP4 66.228.45.110
- s=-
- t=0 0
- a=ice-options:trickle
- a=ice-ufrag:26iqs1932ucrkp
- a=ice-pwd:7rnncil3dqga9q5fl5e3jppobk
- m=text 50659 RTP/AVP 0
- c=IN 66.228.45.110 IP4
- a=mid:text
- a=candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- a=candidate:2 1 udp 2130706431 fe80:0:0:0:38f0:a54b:a8a6:e8b6 8888 typ host
- a=candidate:3 1 udp 1677724415 180.160.213.93 25627 typ srflx raddr 192.168.1.100 rport 8888
- a=candidate:4 1 udp 2815 66.228.45.110 50659 typ relay raddr 180.160.213.93 rport 25627
B的SDP信息:
- v=0
- o=ice4j.org 0 0 IN IP4 66.228.45.110
- s=-
- t=0 0
- a=ice-options:trickle
- a=ice-ufrag:dpmfo1912ud8p2
- a=ice-pwd:2q4c0689j98st3jmbr5k4jgc9k
- m=text 50656 RTP/AVP 0
- c=IN 66.228.45.110 IP4
- a=mid:text
- a=candidate:1 1 udp 2130706431 192.168.1.107 6666 typ host
- a=candidate:2 1 udp 2130706431 fe80:0:0:0:448b:e2e1:7f4b:f0b8 6666 typ host
- a=candidate:3 1 udp 1677724415 180.160.233.193 44639 typ srflx raddr 192.168.1.107 rport 6666
- a=candidate:4 1 udp 2815 66.228.45.110 50656 typ relay raddr 180.160.233.193 rport 44639
交换信息后A的配对过程输出:
- 九月 30, 2014 5:32:53 下午 org.ice4j.ice.Component addRemoteCandidate
- 信息: Add remote candidate for text.RTP: 192.168.1.107:6666/udp/host
- 九月 30, 2014 5:32:53 下午 org.ice4j.ice.Component addRemoteCandidate
- 信息: Add remote candidate for text.RTP: [fe80:0:0:0:448b:e2e8:7f8b:f0b8]:6666/udp/host
- 九月 30, 2014 5:32:53 下午 org.ice4j.ice.Component addRemoteCandidate
- 信息: Add remote candidate for text.RTP: 180.160.233.193:44639/udp/srflx
- 九月 30, 2014 5:32:53 下午 org.ice4j.ice.Component addRemoteCandidate
- 信息: Add remote candidate for text.RTP: 66.228.45.110:50656/udp/relay
- 九月 30, 2014 5:32:55 下午 org.ice4j.ice.Agent startConnectivityEstablishment
- 信息: Start ICE connectivity establishment
- 九月 30, 2014 5:32:55 下午 org.ice4j.ice.Agent initCheckLists
- 信息: Init checklist for stream text
- 九月 30, 2014 5:32:55 下午 org.ice4j.ice.ConnectivityCheckClient startChecks
- 信息: Start connectivity checks!
- 17:32:55.651 [main] INFO com.hankcs.network.IceClient - Agent entered the Running state.
- 九月 30, 2014 5:33:06 下午 org.ice4j.ice.ConnectivityCheckClient processTimeout
- 信息: timeout for pair: 192.168.1.100:8888/udp/host -> 192.168.1.107:6666/udp/host (text.RTP), failing.
- 九月 30, 2014 5:33:16 下午 org.ice4j.ice.ConnectivityCheckClient processTimeout
- 信息: timeout for pair: [fe80:0:0:0:38f0:a54b:a8a6:e8b6]:8888/udp/host -> [fe80:0:0:0:448b:e2e8:7f8b:f0b8]:6666/udp/host (text.RTP), failing.
- 九月 30, 2014 5:33:26 下午 org.ice4j.ice.ConnectivityCheckClient processTimeout
- 信息: timeout for pair: 192.168.1.100:8888/udp/host -> 180.160.233.193:44639/udp/srflx (text.RTP), failing.
- 九月 30, 2014 5:33:36 下午 org.ice4j.ice.ConnectivityCheckClient processTimeout
- 信息: timeout for pair: 66.228.45.110:50659/udp/relay -> 192.168.1.107:6666/udp/host (text.RTP), failing.
- 九月 30, 2014 5:33:36 下午 org.ice4j.ice.Agent incomingCheckReceived
- 信息: Received check from 192.168.1.100:8888/udp/host -> 180.160.233.193:44724/udp/prflx (text.RTP) triggered a check
- 九月 30, 2014 5:33:36 下午 org.ice4j.ice.Agent triggerCheck
- 信息: Add peer CandidatePair with new reflexive address to checkList
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.ConnectivityCheckClient processSuccessResponse
- 信息: Pair succeeded: 192.168.1.100:8888/udp/host -> 180.160.233.193:44724/udp/prflx (text.RTP)
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.ConnectivityCheckClient processSuccessResponse
- 信息: Pair validated: 180.160.213.93:25627/udp/srflx -> 180.160.233.193:44724/udp/prflx (text.RTP)
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.ConnectivityCheckClient processSuccessResponse
- 信息: IsControlling: false USE-CANDIDATE:false
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.ConnectivityCheckClient processSuccessResponse
- 信息: Nomination confirmed for pair: 180.160.213.93:25627/udp/srflx -> 180.160.233.193:44724/udp/prflx (text.RTP)
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Agent entered the Completed state.
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Total ICE processing time: 139649ms
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Stream name: text
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - ------------------------------------------
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Component of stream:RTP,selected of pair:CandidatePair (State=Succeeded Priority=7926347438766424062):
- LocalCandidate=candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- RemoteCandidate=candidate:10000 1 udp 1845496575 180.160.233.193 44724 typ prflx
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - ------------------------------------------
- 17:33:45.695 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Printing the completed check lists:
- 17:33:45.696 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - Check list for stream: text
- 17:33:45.696 [Stun4J Message Processor] INFO com.hankcs.network.IceClient - nominated check list:CheckList. (num pairs=5)
- CandidatePair (State=Failed Priority=9151314442783293438):
- LocalCandidate=candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- RemoteCandidate=candidate:1 1 udp 2130706431 192.168.1.107 6666 typ host
- CandidatePair (State=Failed Priority=9151314442783293438):
- LocalCandidate=candidate:2 1 udp 2130706431 fe80:0:0:0:38f0:a54b:a8a6:e8b6 8888 typ host
- RemoteCandidate=candidate:2 1 udp 2130706431 fe80:0:0:0:448b:e2e8:7f8b:f0b8 6666 typ host
- CandidatePair (State=Failed Priority=7205771498387144702):
- LocalCandidate=candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- RemoteCandidate=candidate:3 1 udp 1677724415 180.160.233.193 44639 typ srflx raddr 192.168.1.107 rport 6666
- CandidatePair (State=Failed Priority=12094594351103):
- LocalCandidate=candidate:4 1 udp 2815 66.228.45.110 50659 typ relay raddr 180.160.213.93 rport 25627
- RemoteCandidate=candidate:1 1 udp 2130706431 192.168.1.107 6666 typ host
- CandidatePair (State=Succeeded Priority=7926347438766424062):
- LocalCandidate=candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- RemoteCandidate=candidate:10000 1 udp 1845496575 180.160.233.193 44724 typ prflx
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.CheckList handleNominationConfirmed
- 信息: Selected pair for stream text.RTP: 192.168.1.100:8888/udp/host -> 180.160.233.193:44724/udp/prflx (text.RTP)
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.Agent checkListStatesUpdated
- 信息: CheckList of stream text is COMPLETED
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.Agent checkListStatesUpdated
- 信息: ICE state is COMPLETED
- 17:33:45.696 [main] INFO com.hankcs.network.IceClient - Component id=1 parent stream=text
- 4 Local candidates:
- default candidate: candidate:4 1 udp 2815 66.228.45.110 50659 typ relay raddr 180.160.213.93 rport 25627
- candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- candidate:2 1 udp 2130706431 fe80:0:0:0:38f0:a54b:a8a6:e8b6 8888 typ host
- candidate:3 1 udp 1677724415 180.160.213.93 25627 typ srflx raddr 192.168.1.100 rport 8888
- candidate:4 1 udp 2815 66.228.45.110 50659 typ relay raddr 180.160.213.93 rport 25627
- 4 Remote candidates:
- default remote candidate: null
- candidate:1 1 udp 2130706431 192.168.1.107 6666 typ host
- candidate:2 1 udp 2130706431 fe80:0:0:0:448b:e2e8:7f8b:f0b8 6666 typ host
- candidate:3 1 udp 1677724415 180.160.233.193 44639 typ srflx raddr 192.168.1.107 rport 6666
- candidate:4 1 udp 2815 66.228.45.110 50656 typ relay raddr 180.160.233.193 rport 44639
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - candidate:1 1 udp 2130706431 192.168.1.100 8888 typ host
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - Remote candinate transport address:180.160.233.193:44724/udp
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - Remote candinate host address:null
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - Remote candinate mapped address:null
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - Remote candinate relayed address:null
- 17:33:45.697 [main] INFO com.hankcs.network.IceClient - Remote candinate reflexive address:180.160.233.193:44724/udp
- org.ice4j.socket.MultiplexingDatagramSocket@46160dbd
- 九月 30, 2014 5:33:45 下午 org.ice4j.ice.Agent logCandTypes
- 信息: Harvester used for selected pair for text.RTP: host
- 17:33:48.700 [TerminationThread] INFO com.hankcs.network.IceClient - Agent entered the Terminated state.
- 17:33:48.700 [TerminationThread] INFO com.hankcs.network.IceClient - ice processing TERMINATED
- 九月 30, 2014 5:33:48 下午 org.ice4j.ice.Agent$TerminationThread run
- 信息: ICE state is TERMINATED
其中,值得注意的是两台设备通过地址对
- Nomination confirmed for pair: 180.160.213.93:25627/udp/srflx -> 180.160.233.193:44724/udp/prflx (text.RTP)
建立了UDP连接。
试验结果
之后B通过键盘输入聊天消息并发送
- hello
- /180.160.213.93:25627 says: AS
- yes
- haha
- /180.160.213.93:25627 says: ZA
A收到消息并回复
- /180.160.233.193:44724 says: hello
- AS
- /180.160.233.193:44724 says: yes
- /180.160.233.193:44724 says: haha
- ZA
一些尝试
将B通过手机热点接入中国电信3G网络后,NAT穿透失败,原因不明。可能此时B属于Symmentric NAT,同时免费的TURN服务器也没有起作用。接下来应当深入研究这几种协议,以及TURN服务器的搭建。
Reference
《NAT穿透解决方案》
http://www.cnblogs.com/javaminer/p/3575282.html
相关推荐
在NAT穿透过程中,主要有两种方法:TCP打洞和UDP打洞。TCP打洞相对复杂,因为TCP的三次握手和状态管理机制,而UDP打洞则相对简单,因为其无连接性。本项目采用的是UDP打洞,具体步骤如下: 1. **建立初始连接**:...
UDP打洞是一种网络技术,主要用于穿透NAT(网络地址转换)网络,使位于不同NAT后的设备能够直接通信。在互联网环境中,许多设备都通过NAT连接,这使得它们拥有私有IP地址,无法直接相互连接。UDP打洞解决了这个问题...
NAT的实现机制对了解UDP打洞技术穿透NAT至关重要。对于NAPT来说,当私网中的计算机(如ClientA)使用UDP协议发送数据到公网的服务器时,NAPT设备会创建一个会话(Session),同时将数据包的源IP地址和源端口号进行...
就是非常有名的“UDP打洞技术”,UDP打洞技术依赖于由公共防火墙和cone NAT,允许适当的有计划的端对端应用程序通过NAT“打洞”,即使当双方的主机都处于NAT之后。这种技术在 RFC3027的5.1节[NAT PROT] 中进行了重点...
UDP打洞技术是一种在NAT(网络地址转换)环境下实现P2P(点对点)通信的方法,尤其在处理子网间通信时非常有用。在Java中,我们可以利用其强大的网络编程API来实现这一功能。以下是对这个技术的详细解释。 ### UDP...
本文将深入探讨C#环境下如何利用UDP协议进行NAT打洞。 **一、理解NAT工作原理** NAT是一种网络技术,用于将私有IP地址转换为公网IP地址,以节省有限的公网IP资源。在NAT背后,设备的通信通过一系列映射规则进行...
Java实现的udp打洞demo、Java实现的udp打洞demo、Java实现的udp打洞demo、
udp 穿透, 传透NAT,打洞。不仅有文档的介绍,将原理介绍清楚,而且有可以直接运行的源码。学习udp打洞的好资料。
UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个位于不同内网的设备间直接通信的方法。在互联网上,许多设备通过NAT连接,这使得它们不能直接与外部网络中的其他设备通信,因为它们都有相同的公共IP地址。UDP...
PeerToPeer打洞 UDP穿墙NAT c源代码
本文将深入探讨UDP穿透NAT的原理以及其实现方法。 NAT工作原理: NAT的主要作用是将内部网络的私有IP地址映射为外部网络的公共IP地址,从而解决IP地址短缺的问题。当内部主机向外部发送数据时,NAT会记录源IP和端口...
C# UDP穿越NAT,UDP打洞,UDP Hole Punching源代码
UDP打洞(UDP Hole Punching)是一种通过网络地址转换(NAT)技术,使位于不同内网中的两台设备能够直接通信的技术。在通常情况下,由于NAT的存在,内部网络中的设备不能直接与外部网络中的设备通信,除非有一个固定...
UDP打洞是一种穿透NAT的技术,通过两个位于NAT后的设备互相发送数据包,诱使NAT为它们打开一个“洞”,允许它们之间的直接通信。这个过程通常涉及三个步骤:首先,客户端A和B分别向公共服务器发送数据包;然后,...
UDP打洞(UDP Hole Punching)是一种通过NAT(网络地址转换)技术,使两个位于不同内网的设备能够直接通信的技术。在C#中实现UDP打洞,主要是利用了UDP协议的特性以及对NAT行为的理解。下面将详细介绍这个过程。 ...
UDP打洞相关的资料,包括原理,说明,以后相关的源码,是学习udp打洞的绝好资料。自己用过,感觉不错。
接着,B根据收到的信息向A的内网地址发送数据,触发NAT打洞。同时,A也向B的内网地址发送数据,尝试在B的NAT上打洞。如果成功,两个设备就能直接通信了。 在实现过程中,还需要考虑以下几点: 1. NAT类型识别:不同...
UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个私有网络内的主机之间直接通信的方法。在互联网上,许多设备由于连接到ISP时采用了NAT,它们的公网IP实际上是路由器分配的内部IP,因此不能直接与其他网络的...
UDP打洞技术是一种在NAT(网络地址转换)环境下实现两个位于不同内网的设备间直接通信的方法。在互联网上,许多用户设备由于IP地址稀缺,通常会通过NAT进行地址转换,这使得它们不能直接与其他内网设备通信。UDP打洞...