阳光男孩 发表于 2009-01-08
2009年1月7日,工业与信息化部发放了三张3G牌照,标志着中国进入了通信技术的新时代。3G的重要特性之一是高速数据链路,移动上网速度大大提高。同时,中国移动也大幅下调了2G网络GPRS上网的资费。可是,语音通话费用仍然按兵不动。作为永远处于弱势的用户,我们却可以通过VoIP网络电话自己实现免费语音通话。
网络电话是下一代网络(NGN)的重要应用之一。“下一代网络”是指10年以后的网络,全部基于软交换(Softswitch)技术。但是,拨打VoIP免费网络电话,并不需要在等待10年。基于现有的TCP/IP网络,我们已经可以使用开源的VoIP软件,实现PC-to-PC的免费语音通话。(注:这里的“免费”,是指不需要支付传统语音通话费用,ADSL/FTTB/3G等上网接入仍然是需要费用的)
下面,我将介绍如何用yate2软件搭建VoIP服务器,并用SIP协议完成语音通话。在我的实例中,使用了局域网内的3台PC,Windows操作系统,接在同一个集线器上,并不是广域网或3G接入。
Yate = Yet Another Telephony Engine,是一款开源的VoIP网络电话软件。它可以作为服务器、也可以作为客户端使用。yate2可以在Linux下运行、也可以在Windows下运行。yate2下载地址
建立服务器这一步不是必须的。yate2支持两个客户端通过IP地址直接连接,而不需要建立服务器。如果你需要支持较多的用户能够互相通话,通常要建立服务器;如果只有2个用户,则可以采用直连方式。
;auth=100、;register=100、;route=100三行,分别去掉前面的分号
[用户名]
password=密码
[sunny]
password=870212
[default],在后面增加一行${username}^$=-;error=noauth^电话号码$=return;called=用户名^15900941215$=return;called=sunny
如果服务成功启动、没有错误提示,你已经正确建立了最简单的yate2网络电话服务器。
再次提醒,不能在运行yate2服务器的计算机上打开yate2客户端软件,否则是无法正常运行的。
如果只有2个用户需要相互通话,就不必劳神建立VoIP服务器了(何况服务器还要占据一台计算机)。yate2支持直连通话,配置方法如下:
yate2支持SIP、H.323、jabber、iax等多种VoIP协议,而先前我选择的是SIP协议。SIP协议定义了一组VoIP网络电话信令,传输层基于UDP协议、端口号为5060;SIP只提供控制信令,并不负责语音数据的编码和传输。
我用Wireshark抓包分析了一次通话过程。这次通话的情况如下:
| 说明 | 主叫方192.168.1.183 <=> 服务器192.168.1.50 | 服务器192.168.1.50 <=> 被叫方192.168.1.101 | 其他头部信息 |
|---|---|---|---|
| 发起呼叫 | => INVITE sip:2@192.168.1.50 | 没有Authorization头,Call-ID:2126492930@192.168.1.50 | |
| <= 100 Trying | |||
| 缺少认证 | <= 401 Unauthorized | 包含WWW-Authenticate头 | |
| 放弃呼叫 | => ACK sip:2@192.168.1.50 | ||
| 发起呼叫 | => INVITE sip:2@192.168.1.50 | From:<sip:u1@192.168.1.50>;tag=1542144666 ,包含Authorization头,Max-Forwards:20,Call-ID:2126492930@192.168.1.50 | |
| <= 100 Trying | |||
| 转发呼叫 | => INVITE sip:u2@192.168.1.50 | From:<sip:u1@192.168.1.50>;tag=831312670 ,没有Authorization头,Max-Forwards:19,Call-ID:495687575@192.168.1.50 | |
| <= 100 Trying | |||
| 振铃 | <= 180 Ringing | ||
| 转发振铃 | <= 180 Ringing | ||
| 接听 | <= 200 OK | ||
| 确认 | => ACK sip:u2@192.168.1.50 | From:<sip:u1@192.168.1.50>;tag=831312670 | |
| 转发接听 | <= 200 OK | ||
| 确认 | => ACK sip:2@192.168.1.50 | From:<sip:u1@192.168.1.50>;tag=1542144666 | |
| 上面的过程,建立了主叫方-服务器、服务器-被叫方的两个VoIP电话连接;主叫方不知道被叫方的用户名和IP地址,被叫方知道主叫方的用户名、但不知道IP地址 | |||
| 现在出现大量的双向RTP数据包,封装了语音数据(甚至可以解码并窃听语音内容);使用随机高端口(在SIP协议的INVITE、200两种报文中,用SDP协议声明了RTP使用的UDP端口、语音编码方式等),经过服务器转发 | |||
| 挂断 | => BYE sip:2@192.168.1.50:5060 | Reason:SIP;text="User hangup" | |
| 主叫方已经停止发送和接收RTP数据包,而被叫方的RTP包仍然不断经服务器转发到达,主叫方回应ICMP Port unreachable消息。 | |||
| <= 100 Trying | |||
| <= 401 Unauthorized | |||
| 挂断 | => BYE sip:2@192.168.1.50:5060 | 这次带上Authorization头 | |
| <= 100 Trying | |||
| 同意挂断 | <= 200 OK | ||
| 通知被叫挂断 | => BYE sip:u2@192.168.1.101:5060 | ||
| 服务器也停止接收RTP数据包,而被叫方的RTP包仍然不断到达,服务器回应ICMP Port unreachable消息。 | |||
| <= 100 Trying | |||
| 同意挂断 | <= 200 OK | ||
假设有人拨打电话号码1。根据regexroute.conf,服务器知道号码1对应于用户u1。那么,服务器怎么知道u1的IP地址呢?这就需要通过接收登录与退出消息来记录用户状态。
REGISTER sip:192.168.1.50
Contact:<sip:u1@192.168.1.183:5060>
Expires:600
To:<sip:u1@192.168.1.50>
REGISTER sip:192.168.1.50
Contact:<sip:u1@192.168.1.183:5060>
Expires:0
To:<sip:u1@192.168.1.50>直接贴出Wireshark的自动分析结果吧~Statistics-VoIP Calls-Graph就可以看到
|Time | 192.168.1.101 | 192.168.1.183 | |3.985 | INVITE SDP |SIP From: sip:anonymous@192.168.1.183 To:sip:0@192.168.1.183 | |(5060) ------------------> (5060) | |4.004 | 100 Trying| |SIP Status | |(5060) <------------------ (5060) | |4.035 | 180 Ringing |SIP Status | |(5060) <------------------ (5060) | |11.818 | 200 OK SDP |SIP Status | |(5060) <------------------ (5060) | |11.826 | ACK | |SIP Request | |(5060) ------------------> (5060) | |11.857 | RTP (g711U) |RTP Num packets:281 Duration:5.597s SSRC:0x1726C94E | |(27392) <------------------ (27824) | |11.954 | RTP (g711U) |RTP Num packets:280 Duration:5.550s SSRC:0x7805579C | |(27392) ------------------> (27824) | |17.495 | BYE | |SIP Request | |(5060) <------------------ (5060) | |17.514 | 100 Trying| |SIP Status | |(5060) ------------------> (5060) | |17.526 | 200 OK | |SIP Status | |(5060) ------------------> (5060) |
与经过服务器的通话相比,直连通话就显得非常简单了:没有身份认证过程,不需要转发信令与RTP数据。