pjsip教程-ICE-NAT passthrough

来源:互联网 发布:新通用顶级域名 编辑:程序博客网 时间:2024/04/29 13:11

http://www.cnblogs.com/ishang/p/3413232.html


PJNATH - Open Source ICE, STUN, and TURN Library 

PJNATH (PJSIP NAT Helper)是一个开源的并且是使用标准协议(STUN,TURN,ICE)提供NAT设备穿越功能的库.

Background

在现今的网络中网络地址转换技术/设备(NAT)很常见,这种技术允许多台主机共享同一个公网地址从而接入网络,其主要目的就是为了缓解IPv4地址的枯竭。 这种技术在普通的服务器/客户端模式下并不存在问题,因为请求总是由客户端发起,并且客户端也不需要维持长时间的维持与服务器的连接。但是NAT技术最大的问题就是使得点对点通信不能进行,比如VoIP.

Introduction to PJNATH

PJNATH库包含了NAT穿越的标准实现,它可以独自应用或者与PJSUA-LIB共同使用,PJSUA-LIB库将PJSIP, PJMEDIA, PJNATH很好的集成在一起,使用方便。.

PJNATH 具有以下特征:

  • STUNbis实现
    该实现遵照RFC 5389.它既提供了现成的STUN网络接口,又提供了基于TURN和ICE的实现更高层次STUN的框架。
  • NAT 类型探测 
    探测通信两端的NAT设备类型,该实现依据 RFC 3489. 然而为了支持ICE,协助NAT穿越的NAT类型的探测已经不被推荐了,但是在故障排除的时候还是有用的,因此提供了NAT类型探测的功能.
  • TURN实现
    TURN 是使用中转服务器进行中继通信的协议,它联合ICE提供了尽可能的高效的通信路径。它的实现符合 draft-ietf-behave-turn-14 草案.
  • ICE实现
    ICE 是发现待通信两端一条或多条可直接通信的路径的协议。它的实现符合draft-ietf-mmusic-ice-19.txt 草案

在将来,我们会实现更多的协议(比如UPnP IGD、SOCKS5).

Library Organization

提供的主要组件如下:

  • STUN: Session Traversal Utilities for NAT
  • TURN: Traversal Using Relays around NAT
  • ICE: Interactive Connectivity Establishment
  • NAT Classification/Detection Tool

除了 NAT Classification/Detection Tool, 每个组件都进一步划分为两个部分:

  • 传输对象
    传输对象是session对象加上指定的  传输/套接字(transport/sockets)  的实现,它给应用程序提供一个直接可以使用的对象。比如,STUN transport, TURN transport以及ICE stream transport

  传输无关/session 层
   session对象(比如 STUN session, TURN session, ICE session)是维护通信协议中session的核心对象,它是与传输无关的(意思是说它自己没有专门用于传输数据的socket,它只有发送和接受数据的接口,至于发送和接收数据时用到的具体的协议它是不关心的)。这样,不管传输层使用的什么协议,开发者都可以重用这个对象,比如使用UDP, TCP或者TLS或者是开发者自己实现的其他某种协议。




Introduction to ICE

  ICE是提供客户端穿越能力的有力武器,只要在两个客户端之间确实存在一条可以通信的路径,ICE肯定就能找到该路径,并且该路径是两个客户端之间通信路径中最高效的最节省资源的(在两个客户端之间经ICE探测后,可能存在多条路径,而ICE保证从它那里获取的路径是最高效的).

  ICE把几个协议结合在一起,在两个客户端之间能提供几条候选路径,这在最大程度上保证了两端通信成功的几率。并且它还提供了在几条通信路径中给出优先顺序的能力,让使用中继(中继的方式代价比较昂贵)的传输方式的优先级降到最低,只有在其他路径都行不通的情况下,才会启用该路径。具体的ICE协商的过程包括以下几个几步:

  • 1:候选地址的收集:ICE客户端收集本地所有可能用于通信的地址。所收集的地址类型分3种:主机候选地址(host candidate),这个地址其实就是本地物理网卡的地址;服务器反射候选地址(server reflexive candidate,其实就是在NAT上关于本地ip的映射地址),这个地址通过STUN服务器获取;中转/中继候选地址(relay candidate),这个地址是在使用中继(relay)的传输方式时,在中继服务器(或者称为TURN服务器)上为本地机器所分配的地址。
  • 2:候选地址的优先策略:一般情况下,使用中继方式而产生的中继候选地址的优先权最低,因为它的代价最昂贵。
  • 3:将本地候选地址编码,把编码后的候选地址传送至对端,双方通过报告/应答的方式进行协商。
  • 4:为候选地址配对儿:将本端的地址与对端的地址一一进行配对。此时应该已经通过某种方式得到了对端的候选地址。
  • 5:为每对儿地址做连接测试。
  • 6:得到结果:由于已经对所有候选地址一一配对,并一一进行连接测试,所以,如果确实存在一个可以通信的路径,ICE肯定会找到他。

Using ICE transport

  ICE stream transport 是一个现成可用的对象,可以使用它来进行ICE操作,而且它为应用程序提供了数据发送与接受的接口,而数据收发的路径,正是经ICE协商过后的高效的路径。

Creating custom ICE transport

  如果ICE stream transport 还是不能满足您的需求,那么您还可以通过使用本软件包提供的ICE Session以及自己的数据传输策略去实现自己的运输层,ICE stream transport 在这方面为您提供了很好的借鉴。


  1:pjsip教程(一)之PJNATH简介

  2:pjsip教程(二)之ICE穿越打洞:Interactive Connectivity Establishment简介

  3:pjsip教程(三)之ICE stream transport的使用

  4:pjsip文档(四)之ICE Session的使用方法

本文原文地址:http://www.pjsip.org/pjnath/docs/html/group__PJNATH__ICE__STREAM__TRANSPORT.htm#ga6fb7cfdde71523f9fce885fd5cad982d

学习使用 ICE stream transport

下面的步骤描述了怎样使用ICE session:

  • 首先初始化结构体: pj_ice_strans_cfg. 这个结构体中包含了ICE stream transport 的配置信息,其中就包括了SUTN以及TURN的配置信息.
  • 使用 pj_ice_strans_create()方法创建stream transport的实例. 该函数的成功调用还需要以下列出的重要的参数:
    • pj_ice_strans_cfg :主配置信息
    • components 的个数
    • 用于产生回调的结构体的实例:pj_ice_strans_cb .
  • 当调用函数pj_ice_strans_create()后,初始化的过程会在后台运行,该初始化过程主要是收集本地的候选地址,最后,当初始化完成,应用程序会在回调函数on_ice_complete 中返回
  • 当想要开启一个媒体流时(例如,想进行视频或语音电话),使用pj_ice_strans_init_ice()创建一个ICE session用于进行打洞.
  • 通常在两个客户端开始打洞之前,双方都需要知道对方的ICE信息(ICE信息,包括用户名,密码以及3组候选地址),那么可以使用下面的方法得到自己的ICE信息:
    • pj_ice_strans_get_ufrag_pwd()
    • pj_ice_strans_enum_cands()
    • pj_ice_strans_get_def_cand()
      应用程序需要将以上信息封装为SDP消息发送至对方.
  • 当应用程序收到远程客户端发来的ICE消息后,就可以开始ICE探测了。开始ICE探测需要调用pj_ice_strans_start_ice()方法.
  • 需要注意的是,PJNATH库不支持直接处理SDP消息,SDP消息的封装与拆解还需应用程序自己实现。
  • 一旦ICE的探测协商开始后,程序最终将会在回调函数on_ice_complete() 中返回。on_ice_complete() 属于结构体: pj_ice_strans_cb.
  • 应用程序在程序运行的任何时刻都能发送或者接受数据,但是ICE的stream transport 对象它能否发送数据,取决于它发送数据时候的状态。状态分为三种:1,探测协商之前,这种状态下可以发送数据,并且使用的是默认的地址;2,探测协商的过程中,此时不能发送数据;3,探测协商完成之后,这种状态下也可以发送数据,且发送数据的地址为探测成功的地址对!
  • 应用程序使用pj_ice_strans_sendto()发送数据,并在pj_ice_strans_cbon_rx_data()回调中返回.
  • 当需要结束媒体Session时,使用pj_ice_strans_stop_ice()回收ICE Session。

关于ICE stream transport,在单次媒体交互完成后,可以选择销毁ICE stream transport或保留它以备后用。保留ICE stream transport有利有弊,好处是减少下次会话时创建它的时间;坏处是应用程序需要与STUN server以及relay server中相应的端口保活,这会无形中造成电量的损耗(consume power), 而电量损耗的高低是移动设备应用的重要参考标准之一。


Detailed Description

这个模块描述的pj_ice_sess对象是PJNATH库的组成部分同时它是与数据包的传输无关的对象(a transport independent)。

ICE Session

ICE Session 是PJNATH库中关于ICE的最底层的抽象,它使用一个单一的媒体流来执行两端的连接检测(双方通过互发数据包进行协商,从而确定一条从A到B可以互通的路径)。ICE Session 使用pj_ice_sess结构体来表示.

此处描绘的ICE Session它不做数据的传输(is independent from any transports),那么这也表明网络的IO得是由应用程序本身或者由它更高的抽象层来执行。使用这个框架,应用程序就可以使用ICE Session来处理所有接收到的数据包,并且该框架也为ICE Session提供了向外发送数据的回调接口。

关于ICE更高级的抽象,请查看ICE stream transport进行了解.

Using The ICE Session

下面是ICE Session的详细使用步骤,当然,开发者也可使用ICE stream transport的API,它对ICE进行了更高级的封装,并且提供了ICE socket的集成。

ICE Session的使用步骤类似于报告/答复模式(offerer and answerer):

  • 使用pj_ice_sess_create()创建ICE Session,其中用户需要指定一下几个参数:
    • STUN 的配置:STUN的一些设置,比如超时时间以及STUN 中需要用到的timer heap、ioqueue实例.
    • Session名称,可用于在日志中标识唯一的会话.
    • 初始化ICE的角色(pj_ice_sess_role).角色的设置可以在初始化完成之后通过pj_ice_sess_change_role()改变。ICE Session也可以在检测到角色冲突之后自动更改。
    • 媒体会话中构件的数目.
    • 触发ICE事件之后的回调函数的设置(pj_ice_sess_cb)
    • 本地ICE用户名称和密码,不过不设置此项时,系统将会随机生成.
  • 使用pj_ice_sess_cand结构体来表示候选者实例,使用pj_ice_sess_add_cand()为每一个构建添加本地地址候选. 每个构件初始化过程中必须至少有一个候选地址,并且所有的控件必须拥有相同的候选地址数,不然会导致配对过程的失败。
  • 创建本地信息的实例(用于描述本地ICE候选者):ICE session没有提供创建该实例的功能,但是应用程序应该实现该功能。如果应用程序使用ICE stream transport的时候,可以使用pj_ice_strans_enum_cands()方法来枚举所有本地候选者。应用程序可使用pj_ice_sess_find_default_cand() 来让ICE Session选择使用在SDP c= and m= lines中的默认的传输地址.
  • 通过某一种信令(比方说SIP)将承载本地信息的实例发送至对端.
  • 当本地接收到对端的应答(包含了对端的候选者信息),应马上解析该消息,建立关于对端的候选者列表,并且通过pj_ice_sess_create_check_list()来建立check lists,这个过程就称为配对.
  • 配对完成后,就可以调用pj_ice_sess_start_check()开始执行连接测试,查看上步中哪个配对是有效的.
  • 最后,在连接测试完成后,应用程序会在pj_ice_sess_create()回调中收到测试结果.

使用pj_ice_sess_send_data()方法来发送数据。如果发送数据的时候是在ICE协商还没完成时,那么ICE session 将直接丢弃该数据并且给调用者返回错误信息;如果是在ICE协商完成后,那么ICE session 将会调用pj_ice_sess_cbon_tx_pkt来发送数据.

由于ICE Session本身没有传输机制,所以应用程序必须把从底层接收到的所有数据包都通过pj_ice_sess_on_rx_pkt()方法传递给ICE Session,ICE Session判断该包是否为STUN包,如果是,则处理;如果不是,则使用on_rx_data回调把数据包向上传递给应用上层.


0 0
原创粉丝点击