我们先学习 uac 的xml,输入命令 ./sipp -sd uac
得到如下内容(部分注释被删除了):
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="Basic Sipstone UAC">
<!-- In client mode (sipp placing calls), the Call-ID MUST be generated by sipp. To do so, use [call_id] keyword. -->
<send retrans="500">
<![CDATA[
INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
To: [service] <sip:[service]@[remote_ip]:[remote_port]>
Call-ID: [call_id]
CSeq: 1 INVITE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Type: application/sdp
Content-Length: [len]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv response="100"
optional="true">
</recv>
<recv response="180" optional="true">
</recv>
<recv response="183" optional="true">
</recv>
<!-- By adding rrs="true" (Record Route Sets), the route sets are saved and used for following messages sent. Useful to test against stateful SIP proxies/B2BUAs. -->
<recv response="200" rtd="true">
</recv>
<!-- Packet lost can be simulated in any send/recv message by adding the 'lost = "10"'. Value can be [1-100] percent. -->
<send>
<![CDATA[
ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
Call-ID: [call_id]
CSeq: 1 ACK
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Length: 0
]]>
</send>
<!-- This delay can be customized by the -d command-line option or by adding a 'milliseconds = "value"' option here. -->
<pause/>
<!-- The 'crlf' option inserts a blank line in the statistics report. -->
<send retrans="500">
<![CDATA[
BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[pid]SIPpTag00[call_number]
To: [service] <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
Call-ID: [call_id]
CSeq: 2 BYE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Length: 0
]]>
</send>
<recv response="200" crlf="true">
</recv>
<!-- definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<!-- definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>
一个xml总是以
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
开头,其中sipp.dtd是一个XML文档构建模块,可以在sipp中所在的目录找到。
所有内容都必须包含在 <scenario></scenario>
节点内,name属性可以用于描述该xml的功能。
接下看到 <send></send>
,很容易理解,这是一个发送消息命令,sipp中消息命令总共有:<send>,<recv>,<nop>,<pause>,<sendCmd>和<recvCmd>
。
每个命令具有不同的用途,通过这些命令,我们来填写一个带有逻辑功能的xml。
所有命令都有共有属性,我们将在后面讲解共有属性。除了共有属性外,每个命令还有自己特有的属性,retrans="500"
是send命令所包含的特有属性。
所有的共有属性和特有属性可以在 ./docs/scenarios/ownscenarios.rst
中查找到,
每个命令所包含的属性各不相同,send命令有以下几种特有属性:
retrans
:重发报文时间,用于使用 udp 协议时,定义报文重发送时间,此处表示500毫秒重发。
lost
:模拟丢包率,表示发送的丢包率为 10% 。
start_txn
:用来记录响应时间,该属性记录本次发送的消息的 branch id,以在收到回应时能够精确匹配,若没有此属性则根据 Cseq 匹配。
<send start_txn="invite">
存储本次会话(由branch id 唯一指定)消息,名称记为“invite“。
ack_txn
:用来记录响应时间,该属性与 start_txn指定的消息对应,这两个消息必须成对出现,否则报错。
<send ack_txn="invite">
对应上面发送的名为 “invite” 的会话消息。
从示例可以看出,在“send”命令内部,必须要将待发送的 sip 消息括入 <![CDATA
和 ]]>
中间,在这中间的所有内容将会被发送到远端系统。
同时,你可能也注意到了,在这个示例中有一些特殊的关键词,比如:[service]
,[remote_ip]
,
这些关键词用来指示 sipp 将要用这些关键词做什么样的事情,可以认为就是一个变量。
所有的变量都可以去./docs/scenarios/keywords.rst文件中查找到, 我们用下面表格来列出该示例中所有的变量:
序号 | 变量 | 值 |
---|---|---|
1 | service | service |
2 | remote_ip | 10.9.109.232 |
3 | remote_port | 5060 |
4 | transport | UDP |
5 | local_ip | 10.9.109.232 |
6 | local_port | 5061 |
7 | branch | z9hG4bK-6563-1-0 |
8 | pid | 6563 |
9 | call_number | 1 |
10 | call_id | 1-6563@10.9.109.232 |
11 | len | 135 |
12 | local_ip_type | 4 |
13 | media_ip_type | 4 |
14 | media_ip | 10.9.109.232 |
15 | media_port | 6004 |
16 | peer_tag_param | ;tag = 6529SIPpTag011 |
各个变量如何计算得来,sipp获取的方式都不太一样,我们以上面所有变量为例:
-
第一种方式:利用
./sipp
参数带过来,通过参数后面的值,来给变量赋值。
查看./src/sipp.cpp::struct sipp_option options_table[] = {...}
结构体,该结构体实际上是用于解析参数,可以看到包含service行:{"s", "Set the username part of the request URI. Default is 'service'.", SIPP_OPTION_STRING, &service, 1},
-s
参数后面内容将放置在service全局变量中,然后解析xml文件时,碰到[]就会认为是变量,将会去./src/message.cpp
中比配struct KeywordMap SimpleKeywords[] = {...}
,
比配出对应的值,转成 MessageCompType type,需要发送数据时,可以看到组装数据函数./src/call.cpp::call::createSendingMessage
,会找到对应 MessageCompType type 的变量填充。通过查找
sipp_option options_table[] = {...}
,可以发现上面service、local_ip、media_ip
,分别对应的参数是-s、-i、-mi
,另外transport
依据-t
后面参数来决定是 UDP、TCP或者TLS。 -
第二种方式:也是通过./sipp参数带过来,但是实际填入数据报文时,通过函数加工计算得来。
sipp remote_host[:remote_port] [options]
,这是sipp一般模式命令。我们输入的远程网络地址将会放到remote_host变量中,
当建立连接时,./src/socket.cpp::open_connections
函数计算远程端ip和本地端ip,
这时候会更改变量remote_ip、remote_port、local_ip、local_port
值。参数
-mp
后面的内容会填入user_media_port
变量中,media_port
变量以user_media_port
变量为起始,去绑定端口,如失败,则media_port += 2
。 -
第三种方式:直接通过程序计算得来。
pid
变量会在程序一启动时,通过pid = getpid();
来获得pid值。
branch变量是通过
("z9hG4bK-%u-%u-%d", pid, number, P_index + comp->offset)计算得来。
call_number变量就是以发送次数来确定。 类似有
call_id变量、
len` 变量。 -
第四种方式:通过网络通讯获取对方发送数据报文得来。
在与服务器通讯时,会建立tag,对方的tag值为peer_tag
变量,peer_tag_param
变量计算公式为(";tag=%s", peer_tag)
。
我们继续看到 <recv></recv>
命令,可以看到两个属性 response、optional
,都是 recv
命令特有属性。
recv
特有属性有:
-
response:指定 sipp 期望收到的 SIP消息代码,如 1xx,2xx,3xx 等。
<recv response="200">
表示 sipp 期望收到代码为200的消息。 -
request:指定 sipp 期望到收的 SIP 请求消息,如:INVITE、ACK、BYE、REGISTER、CANCEL、OPTIONS等。
<recv request="ACK">
表示sipp期望收到 ACK 请求。 -
optional:指定 sipp 期望收到的消息是可选的,对端可以回这个期望的消息,也可以没有回这个期望的消息。
如果 sipp 收到一个消息,sipp 先检查这个消息是否匹配一个标记为optional
的消息,如果不匹配则标记为unexpected
。
当optional
设置为global
时,sipp 在收到一个消息时会检查脚本的全部步骤。
<recv response="100" optional="true">
表示 sipp期望收到代码为 100 的消息,但如果没有收到也没有关系。 -
rrs: Record Route Set,即路由记录设置,如果该属性被设置为
true
,则收到的消息中的消息头Record-Route
会被存储,并可以通过[route]
关键词调用。 -
auth:鉴权认证。如果该属性被设置为“true”,则消息中的消息头
<recv response="407" auth="true">
。
Proxy-Authenticate:
会被存储并可以用来生成认证用的关键词[authentication]
。 -
lost:模拟丢包率。
-
timeout:设置超时,如果期望的消息在指定的时间里面没有收到,除非指定了
ontimeout
标否,否则呼叫将被终止。 -
ontimeout:在超时之后跳到指定标号。例:在 100s 内没有收到消息 100 则跳到标号 5。
<recv response="100" timeout="100000" ontimeout="5"> </recv>
-
rtd:停止值中所对应的“响应时间值”计时器,便于统计响应时间。如
<send rtd="2">
当这个消息被发送的时候会停止 2 号计时器。
<send rtd="invite">
当这个消息被发送的时候会停止 invite计时器。<recv response="200" rtd="true">
当收到这个200 消息时,会停止从1开始到这个命令的所有计时器。