首页
学习
活动
专区
圈层
工具
发布
50 篇文章
1
C语言中如何实现数据帧封装与解析
2
【熟视C语言】如何快速的了解一个库函数(C语言讲解,以string.h中的部分库函数为例)
3
C语言代码封装MQTT协议报文,了解MQTT协议通信过程
4
NV12数据格式转H265编码格式实现过程
5
基于Modbus协议实现Openplc与Kingview的仿真通讯与模拟测试
6
onvif协议最新版本_接口协议测试工具
7
linux后台开发常用调试工具
8
C/C++开发人员要了解的几大著名C/C++开源库[通俗易懂]
9
适用于嵌入式环境的加速计算库
10
Linux下WebRTC框架Janus编译过程
11
探索嵌入式应用框架(EAF)
12
[C&C++]联合体union的特征及用其进行传输
13
联合体和结构体一起解析数据
14
国标GB28181协议客户端开发(四)实时视频数据传输
15
6.1 C/C++ 封装字符串操作
17
C语言进阶——自定义类型
18
干货 | 结构体、联合体嵌套使用的一些实用操作
19
C语言的面向对象编程
20
QT应用编程: 编写低功耗BLE蓝牙调试助手(Android系统APP)
21
设计模式之接口隔离原则C++实现
22
嵌入式软件开发的框架思维
23
通过面向对象设计串口协议
24
QT应用编程: 开发串口调试助手
25
一种高效的串口自定义16进制通信协议的嵌入式应用开发解决方案
26
嵌入式中状态机的几种骚操作
27
【干货】用FreeRTOS搭建Event-Driven应用框架
28
嵌入式开发基础之任务管理(线程管理)
29
SIP菜鸟如何学SIP
30
Linux下使用libuvc读取控制USB免驱摄像头
31
Linux 使用strace命令查找进程卡死原因
32
84-OOP之组合
33
如何调试多线程程序
34
GDB多线程调试分析
35
GDB多线程多进程调试
36
一个简单实用的线程基类
37
OpenThread是世界上最舒心的跨平台多线程并发库
38
OpenMiniServer是一个超迷你、 超易用的C++高并发跨平台服务器框架
39
OpenSocket是跨全平台的高性能高并发网络库
40
一个C++多线程TCP服务Demo
41
一文搞懂网络库的分层设计!
42
实现一个接收多路RTP流,输出一路RTMP流的简单MCU
43
谈谈嵌入式应用软件人机界面开发的菜单框架编写
44
union 的概念及在嵌入式编程中的应用
45
让终端支持https,移植OpenSSL和libcurl到嵌入式linux,遇到的问题总结
46
日常工作中的设计:解耦和封装
47
一种简易的嵌入式设备系统日志记录方法
48
PLC和计算机通信的数据采集方法和传输监控的实现(1)
49
C++随笔(五)三种实现串口通信的方式
50
开源一个自己写过的MQTT 客户端调试工具

SIP菜鸟如何学SIP

在学习SIP之前,我们首先要了解什么是SIP

SIP是一个应用层的控制协议,可以用来建立、修改、和终止多媒体会话(或者会议)例如Internet电话。SIP在建立和维持终止多媒体会话协议上,支持5个方面:

  • 用户定位:检查终端用户的位置,用于通讯。
  • 用户有效性:检查用户参与会话的意愿程度。
  • 用户能力:检查媒体和媒体参数。
  • 建立会话:“ringing”,建立会话参数在呼叫方和被叫方。
  • 会话管理:包括发送和终止会话,修改会话参数,激活服务等等。

了解完SIP之后我们应该来认识一下SIP协议的格式

SIP消息体结构与HTTP协议结构相似,均由三部分组成:

  • 请求行(request-line) or 状态行(status-line)
  • 消息头(header)
  • 正文(body)

请求行:

  • 格式:Method Request-URI SIP-Version
  • eg:INVITE sip:10087@dev.xswitch.cn SIP/2.0
  • method的主要几种消息方法:

状态行:

  • 格式:SIP-Version Status-Code
  • 如:SIP/2.0 200 OK

下面简单列出一些常见的状态码:

消息头:

代码语言:javascript
复制
INVITE sip:10087@dev.xswitch.cn SIP/2.0
Record-Route: <sip:192.168.31.188:15060;lr=on;nat=yes>
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.1c537238ae43750e62a423ddf7fe078c.0
Via: SIP/2.0/UDP 172.18.0.1:61789;received=172.18.0.1;rport=61789;branch=z9hG4bKPjTu0TroBVkc2BuxTbvQ4ODaYdk83-ljf9
Max-Forwards: 69
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: sip:10087@dev.xswitch.cn
Contact: <sip:10086@172.18.0.1:61789;ob;alias=172.18.0.1~61789~1>
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, norefersub
User-Agent: Telephone 1.5.2
Content-Type: application/sdp
Content-Length:   471

各消息头简介:

消息体:

消息编码协议头:

代码语言:javascript
复制
v=0
o=- 3874185567 3874185567 IN IP4 172.18.0.1
s=pjmedia
b=AS:117
t=0 0
a=X-nat:0
m=audio 4000 RTP/AVP 96 9 8 0 101 102
c=IN IP4 172.18.0.1
b=TIAS:96000
a=rtpmap:96 opus/48000/2
a=fmtp:96 useinbandfec=1
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:101 telephone-event/48000
a=fmtp:101 0-16
a=rtpmap:102 telephone-event/8000
a=fmtp:102 0-16
a=rtcp:4001 IN IP4 172.18.0.1
a=ssrc:2122978608 cname:0d505733158cdc19

完整流程Demo:

环境说明:

  • 环境:docker + kamailio + freeswitch
  • 本地 en0 网卡地址:192.168.31.188
  • Kamailio IP:172.18.0.188 代理端口:15060
  • FreeSWITCH IP:172.18.0.14

INVITE消息呼叫源 192.168.31.188 分机号 10086 发送一个会话请求,呼叫10087的分机,注意此时的call-id:01YPOzp4pT.DDQs5VapOAu9EEy7kss3I,留着后面做对比。

代码语言:javascript
复制
INVITE sip:10087@dev.xswitch.cn SIP/2.0
Record-Route: <sip:192.168.31.188:15060;lr=on;nat=yes>
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.1c537238ae43750e62a423ddf7fe078c.0
Via: SIP/2.0/UDP 172.18.0.1:61789;received=172.18.0.1;rport=61789;branch=z9hG4bKPjTu0TroBVkc2BuxTbvQ4ODaYdk83-ljf9
Max-Forwards: 69
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: sip:10087@dev.xswitch.cn
Contact: <sip:10086@172.18.0.1:61789;ob;alias=172.18.0.1~61789~1>
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Supported: replaces, 100rel, norefersub
User-Agent: Telephone 1.5.2
Content-Type: application/sdp
Content-Length:   471
P-SRC-IP: 172.18.0.1

100 Trying 消息:

freeswitch告诉客户端,已收到请求,正准备呼叫目标10087

注意,这里的via头域的172.18.0.188,是kam的ip地址,因为此处是kam负责dispatch代理分发的。

至此,10086和fs的通话已经建立。对于fs这种b2bua的模式来说已经生成了一个channel。接下来,freeswitch将通过sip协议生成另一个channel。

代码语言:javascript
复制
SIP/2.0 100 Trying
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.1c537238ae43750e62a423ddf7fe078c.0;received=172.18.0.188
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: sip:10087@dev.xswitch.cn
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 INVITE
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Content-Length: 0

生成另一个channel:

再次出现了一个invite消息头,但是call-id变了,变成了6e0d4d6e-1d00-4326-b82d-f2eb3bac236e。Via头域里的ip地址也变成了freeswtich容器的地址172.18.0.14,表明fs开始着手呼叫目标号码。

代码语言:javascript
复制
INVITE sip:10087@dev.xswitch.cn;dest=extension SIP/2.0
Via: SIP/2.0/UDP 172.18.0.14:17060;rport;branch=z9hG4bK9FNpKQ6v9aSea
Route: <sip:172.18.0.188:15060>
Max-Forwards: 68
From: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
To: <sip:10087@dev.xswitch.cn;dest=extension>
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
CSeq: 58044591 INVITE
Contact: <sip:mod_sofia@172.18.0.14:17060>
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Allow-Events: talk, hold, conference, refer
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 248
P-SRC-IP: 172.18.0.1
X-FS-Session: c540ce3b-ef41-4cd8-b1ef-4081f678baa0
X-User-Fallback-Proxy: sip:192.168.7.8:5080;transport=tcp
X-FS-Support: update_display,send_info
Remote-Party-ID: "10086USER" <sip:10086@172.18.0.14>;party=calling;screen=yes;privacy=off

再次出现100 trying:

回复10087目标号码已经准备好了。注意,此时的回复是目标端10087回复给freeswitch的。

代码语言:javascript
复制
SIP/2.0 100 trying -- your call is important to us
Via: SIP/2.0/UDP 172.18.0.14:17060;rport=17060;branch=z9hG4bK9FNpKQ6v9aSea;received=172.18.0.14
From: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
To: <sip:10087@dev.xswitch.cn;dest=extension>
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
CSeq: 58044591 INVITE
Server: kamailio (5.5.2 (x86_64/linux))
Content-Length: 0

183 progres消息:

这个是freeswiitch回复给10086客户端的,此时10087振铃,10086播放回铃音。

代码语言:javascript
复制
SIP/2.0 183 Session Progress
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.1c537238ae43750e62a423ddf7fe078c.0;received=172.18.0.188
Via: SIP/2.0/UDP 172.18.0.1:61789;received=172.18.0.1;rport=61789;branch=z9hG4bKPjTu0TroBVkc2BuxTbvQ4ODaYdk83-ljf9
Record-Route: <sip:192.168.31.188:15060;lr=on;nat=yes>
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: <sip:10087@dev.xswitch.cn>;tag=5K0jvDUcF5QtB
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 INVITE
Contact: <sip:10087@172.18.0.14:17060;transport=udp>
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Accept: application/sdp
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Allow-Events: talk, hold, conference, refer
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 260
Remote-Party-ID: "10087" <sip:10087@dev.xswitch.cn>;party=calling;privacy=off;screen=no

200 OK消息:

当10087拿起电话接听后,回复200给freeswitch。

代码语言:javascript
复制
IP/2.0 200 OK
Via: SIP/2.0/UDP 172.18.0.14:17060;rport=17060;received=172.18.0.14;branch=z9hG4bK9FNpKQ6v9aSea
Record-Route: <sip:192.168.31.188:15060;transport=tcp;lr;r2=on;nat=yes>
Record-Route: <sip:192.168.31.188:15060;lr;r2=on;nat=yes>
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
From: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
To: <sip:10087@dev.xswitch.cn;dest=extension>;tag=B5e4EsqcqeTGk30gdo1X0way6hjX8t04
CSeq: 58044591 INVITE
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Contact: <sip:10087@172.18.0.1:57950;transport=TCP;ob;alias=172.18.0.1~57950~2>
Supported: replaces, 100rel, norefersub
Content-Type: application/sdp
Content-Length:   311

ACK消息:

freeswitch收到200之后,回复10087一个ack,表明已经收到,然后会给10086回200。

代码语言:javascript
复制
ACK sip:10087@172.18.0.1:57950;transport=TCP;ob;alias=172.18.0.1~57950~2 SIP/2.0
Via: SIP/2.0/UDP 172.18.0.14:17060;rport;branch=z9hG4bKaSeFNjQ06KF1N
Route: <sip:192.168.31.188:15060;lr;r2=on;nat=yes>
Route: <sip:192.168.31.188:15060;transport=tcp;lr;r2=on;nat=yes>
Max-Forwards: 70
From: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
To: <sip:10087@dev.xswitch.cn;dest=extension>;tag=B5e4EsqcqeTGk30gdo1X0way6hjX8t04
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
CSeq: 58044591 ACK
Contact: <sip:mod_sofia@172.18.0.14:17060>
Content-Length: 0

回送给客户端的200 ok消息:

代码语言:javascript
复制
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.1c537238ae43750e62a423ddf7fe078c.0;received=172.18.0.188
Via: SIP/2.0/UDP 172.18.0.1:61789;received=172.18.0.1;rport=61789;branch=z9hG4bKPjTu0TroBVkc2BuxTbvQ4ODaYdk83-ljf9
Record-Route: <sip:192.168.31.188:15060;lr=on;nat=yes>
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: <sip:10087@dev.xswitch.cn>;tag=5K0jvDUcF5QtB
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 INVITE
Contact: <sip:10087@172.18.0.14:17060;transport=udp>
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Allow-Events: talk, hold, conference, refer
Session-Expires: 120;refresher=uas
Content-Type: application/sdp
Content-Disposition: session
Content-Length: 260
Remote-Party-ID: "Outbound Call" <sip:10087@dev.xswitch.cn>;party=calling;privacy=off;screen=no

客户端再回一个ack消息给freeswitch:

代码语言:javascript
复制
ACK sip:10087@172.18.0.14:17060;transport=udp SIP/2.0
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK986d.10b2bc120531367a8df6e82cbba0ef11.0
Via: SIP/2.0/UDP 172.18.0.1:61789;received=172.18.0.1;rport=61789;branch=z9hG4bKPjqRtG0BNHXz3lieovgGbagVMf1bgveYpB
Max-Forwards: 69
From: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
To: sip:10087@dev.xswitch.cn;tag=5K0jvDUcF5QtB
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 10584 ACK
Content-Length:  0

BYE消息:

此时的from是10087,可见是10087这个被叫主动发出的挂机请求给freeswitch。

代码语言:javascript
复制
BYE sip:mod_sofia@172.18.0.14:17060 SIP/2.0
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK71b.ab931f7decc319df14337c8822b5278b.0;i=3
Via: SIP/2.0/TCP 172.18.0.1:57950;received=172.18.0.1;rport=57950;branch=z9hG4bKPje2pt4x0eBwbYGx1ki8iKkZiCUhRD8oCD;alias
Max-Forwards: 69
From: <sip:10087@dev.xswitch.cn;dest=extension>;tag=B5e4EsqcqeTGk30gdo1X0way6hjX8t04
To: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
CSeq: 16442 BYE
User-Agent: Telephone 1.5.2
Content-Length:  0

freeswitch收到bye消息之后,回复200,删除被叫这个channel。

代码语言:javascript
复制
SIP/2.0 200 OK
Via: SIP/2.0/UDP 192.168.31.188:15060;branch=z9hG4bK71b.ab931f7decc319df14337c8822b5278b.0;i=3;received=172.18.0.188
Via: SIP/2.0/TCP 172.18.0.1:57950;received=172.18.0.1;rport=57950;branch=z9hG4bKPje2pt4x0eBwbYGx1ki8iKkZiCUhRD8oCD;alias
From: <sip:10087@dev.xswitch.cn;dest=extension>;tag=B5e4EsqcqeTGk30gdo1X0way6hjX8t04
To: "10086USER" <sip:10086@172.18.0.14>;tag=6vSBy8BgceeDQ
Call-ID: 6e0d4d6e-1d00-4326-b82d-f2eb3bac236e
CSeq: 16442 BYE
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Content-Length: 0

同时,freeswitch也会给原叫回bye,同时会携带挂机原因Reason:Q.850;cause=16;text="NORMAL_CLEARING"

代码语言:javascript
复制
BYE sip:10086@172.18.0.1:61789;ob;alias=172.18.0.1~61789~1 SIP/2.0
Via: SIP/2.0/UDP 172.18.0.14:17060;rport;branch=z9hG4bKB277pD833v5KH
Route: <sip:192.168.31.188:15060;lr=on;nat=yes>
Max-Forwards: 70
From: <sip:10087@dev.xswitch.cn>;tag=5K0jvDUcF5QtB
To: "10086USER" <sip:10086@dev.xswitch.cn>;tag=xav30sssdGzvtGLUJV7uwjtvKVZra6nl
Call-ID: 01YPOzp4pT.DDQs5VapOAu9EEy7kss3I
CSeq: 58044593 BYE
User-Agent: FreeSWITCH-mod_sofia/1.10.8-dev+git~20211222T004816Z~c7280c7e93~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY
Supported: timer, path, replaces
Reason: Q.850;cause=16;text="NORMAL_CLEARING"
Content-Length: 0

客户端收到bye之后回复200给freeswitch,freeswitch挂断原叫这个channel。

至此,整个SIP协议流程完毕。

下面,通过一个简单的图整理一下整个流程:

下一篇
举报
领券