GeorgeYang'Blog

my technology blog

Centos安装turn stun服务器,p2p通信JAVAdemo

阅读:1640 创建时间:17-01-13 23:44:31 tags:java,p2p

最近闲的有点无聊,了解一下p2p,废话不多说,上内容。

P2P

利用udp协议通过路由穿透,实现广域网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端通讯来完成交互。

  • TURN

TURN解决NAT穿透的思路与STUN类似,都是通过修改应用层中的私网地址达到NAT穿透。 与STUN不同的是,TURN是通过两方通讯的“中间人”的方式实现穿透,在这种方式下, 要进行通讯的两方分别与位于公网上的TURN服务器建立各自的连接进行通讯,由服务器负 责在两方之间进行数据转发。要达到这个目的,实现TURN客户端的终端必须在通讯开始前 与TURN服务器进行交互,得到服务器为其临时分配的位于TURN服务器上的公网地址,客户端使用它替换位于应用层中的私网地址。

  • ICE

与STUN和TURN相比,ICE并非是解决NAT穿透问题的协议,而是一个框架,在这个框架中, 可以整合其他现存的NAT穿透协议,如STUN、TURN、RSIP等。区别于其他的NAT穿透解 决方案,ICE是一种探索和更新式的解决方案,通过搜集自身和对端尽可能多的网络信息(各种网络地址),尝试在这些地址间建立数据通道,并在这一过程中不断更新先前收集到的信息,从而找出和选择能够进行NAT穿透的数据通道。

详细信息简介请浏览这里

两台客户主机建立P2P过程

  • 如果两台主机NAT Type: Full Cone

使用stun服务器建立两台主机的通信

image description

  • 如果其中一台不支持UDP传输或两台都不支持

使用turn服务器做数据中转

image description

  • ICE是整合STUN和TURN的完善框架。

ICE信息的描述格式通常采用标准的SDP,其全称为Session Description Protocol,即会话描述协议. SDP只是一种信息格式的描述标准,不属于传输协议,但是可以被其他传输协议用来交换必要的信息,如SIP和RTSP等.

SDP信息详情

原理是STUN/TURN结合,读者可自行了解

TURN/STUN服务器搭建

作者用的是centos系统,所以下面描述centos的安装方法

 wget http://ncu.dl.sourceforge.net/project/turnserver/turnserver-0.7.3.tar.bz2
 tar -xvf turnserver-0.7.3.tar.bz2
 # 下载并安装libconfuse依赖:
 wget  http://nongnu.askapache.com//confuse/confuse-2.7.tar.gz
 tar -zxvf confuse-2.7.tar.gz 
 cd confuse-2.7
 ./configure --prefix=/usr
 make && make install
 # 安装flex依赖
 yum install flex  
 cd ../turnserver-0.7.3
 ./configure --enable-debug-build
 make && make install

详细安装教程:http://yipeng.info/p/5710b092fb60bc8e454951bc

将配置文件放至软件读取的 /etc/turnserver.conf位置,修改配置文件到/etc/turnusers.txt,并指定TURN用户,或使用该命令指定:

 turnserver --userdb /etc/turnusers.txt

检查是否已经运行:

 netstat -na | grep 3478
 或
 ps aux | grep stun

JAVA测试STUN服务器

  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();
         }

     }

完整代码:https://github.com/hankcs/IceNAT 该项目缺少:ice4j,请使用https://github.com/jitsi/ice4j以maven下载依赖库后,集成到IceNAT项目。

几个java库类实现NAT穿透

 pjnath - pjnath(PJSIP NAT助手)是一个开源库通过使用基于标准的协议如眩晕,转,和冰提供NAT功能。

 PJSIP JNI - Java JNI封装在

 jstun PJSIP -基于Java眩晕(用户数据报协议简单的遍历(UDP)通过网络地址转换(NAT))实施

 FreeCast节点可以执行STUN请求确定其公共地址。NAT穿越技术要求。使用jstun API(HTTP:/ / jstun。javawi。德/

几个STUN服务器:

 s1.taraba.net  208.91.197.54   3478    JP
 s2.taraba.net  208.91.197.54   3478    JP
 s1.voipstation.jp  113.32.111.126  3478    JP
 s2.voipstation.jp  113.32.111.127  3478    JP

 stunserver.org
 stun.xten.com
 stun.softjoys.com:3478

 stun.l.google.com:19302
 stun1.l.google.com:19302
 stun2.l.google.com:19302
 stun3.l.google.com:19302
 stun4.l.google.com:19302
 stun01.sipphone.com
 stun.ekiga.net
 stun.fwdnet.net
 stun.ideasip.com
 stun.iptel.org
 stun.rixtelecom.se
 stun.schlund.de
 stunserver.org
 stun.softjoys.com
 stun.voiparound.com
 stun.voipbuster.com
 stun.voipstunt.com
 stun.voxgratia.org
 stun.xten.com


 stun.voipbuster.com    287ms
 stun.wirlab.net    320ms
 stun.ideasip.com   397ms
 stun.iptel.org 405ms
 stun.schlund.de    425ms
 numb.viagenie.ca   434ms
 stun.voxgratia.org 452ms
 stun.ekiga.net 526ms
 stun.voipstunt.com 571ms
 stunserver.org 780ms