团队博客

聊聊 SIPp uac.xml

小樱桃科技  2025-05

SIPp 是一款轻量级的 SIP 协议性能测试工具,uac.xml 是其内置的用户代理客户端(UAC)场景脚本,常用于模拟呼叫发起端进行压力测试。本文先介绍 Debian 12 环境下 SIPp 的安装、uac.xml 的获取及基础压力测试脚本编写,再重点说明如何修改 uac.xml 以支持经过 Kamailio 代理再对接 FreeSWITCH 的场景。

基础环境准备与 uac.xml 获取

在 Debian 12 系统中,SIPp 可通过 apt 包管理器直接安装,操作十分便捷,仅需执行以下命令:

apt-get install -y sip-tester

安装完成后,默认版本为 3.6.1。接下来,通过 SIPp 内置命令导出默认的 uac.xml 脚本,命令如下:

sipp -sd uac > uac.xml

执行后,当前目录会生成 uac.xml 文件,这是后续压力测试的基础脚本。

基础压力测试脚本编写

为了简化测试操作,我们可以编写一个 shell 脚本(命名为 stress.sh),将 SIPp 测试参数集中配置。脚本内容及参数说明如下:

#!/bin/bash

# 本地IP地址(SIPp 运行主机)
LOCAL_IP=192.168.1.100
# 本地端口(SIPp 监听端口)
LOCAL_PORT=6666
# 目标FreeSWITCH地址及端口
FS=192.168.1.200:5080
# 呼叫成功后延时(毫秒)
DELAY=20000
# 呼叫速率(每秒呼叫数)
RATE=30
# 最大并发通道数
LIMIT=600
# 总呼叫次数(达到后停止测试)
TOTAL=10000

# 启动SIPp压力测试
sipp -sf uac.xml -r $RATE -d $DELAY -l $LIMIT -m $TOTAL -i $LOCAL_IP -p $LOCAL_PORT $FS

核心参数说明

  • -r $RATE:设置呼叫速率,单位为“每秒呼叫数”;

  • -d $DELAY:呼叫建立成功后,保持通话的延时时间,单位为毫秒;

  • -l $LIMIT:限制最大并发呼叫通道数,避免过度占用资源;

  • -m $TOTAL:设置总呼叫次数,当呼叫次数达到该值时,SIPp 自动结束测试;

  • -i $LOCAL_IP:指定本地 SIP 协议绑定的 IP 地址;

  • -p $LOCAL_PORT:指定本地 SIP 协议监听的端口;

  • $FS:目标 FreeSWITCH 服务器的地址和端口(格式:IP:端口)。

脚本执行步骤

  1. 添加脚本执行权限:chmod +x stress.sh

  2. 启动压力测试:./stress.sh

注意:执行测试前,需确保 FreeSWITCH 已配置好对应的拨号计划(dialplan),否则无法正常建立呼叫,具体拨号计划配置此处不展开说明。

uac.xml 适配 Kamailio 代理场景的修改

默认的 uac.xml 脚本仅支持直接呼叫 FreeSWITCH,无法适配“经过 Kamailio 代理服务器再转发至 FreeSWITCH”的架构(常见于生产环境的负载均衡、权限控制场景)。需通过以下 3 处修改,让脚本支持代理转发逻辑。

编码格式优化(支持中文注释)

默认 uac.xml 第一行的编码格式为 ISO-8859-1,不支持中文注释。将其修改为 UTF-8,方便后续添加中文说明:

原内容:

<?xml version="1.0" encoding="ISO-8859-1" ?>

修改后:

<?xml version="1.0" encoding="UTF-8" ?>

接收 200 OK 时记录路由集

当呼叫经过 Kamailio 代理时,代理会在 200 OK 响应中携带 Record-Route 头(路由集),后续的 ACK、BYE 消息需沿该路由集返回。需在接收 200 响应的配置中添加 rrs="true" 参数(rrs 即 Record-Route Sets 的缩写,用于保存路由集):

原内容:

  <recv response="200" rtd="true">
  </recv>

修改后:

  <recv response="200" rtd="true" rrs="true">
  </recv>

调整 ACK、BYE 消息的请求地址与路由头

默认的 ACK、BYE 消息会直接发送到 FreeSWITCH 地址,经过代理时需改为发送到路由集中的下一跳地址(通过[next_url] 变量获取),同时添加 [routes] 变量携带完整路由集。

ACK 消息修改

原内容:

  <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>

修改后:

  <send>
    <![CDATA[

      ACK [next_url] 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
      [routes]
      Contact: sip:sipp@[local_ip]:[local_port]
      Max-Forwards: 70
      Subject: Performance Test
      Content-Length: 0

    ]]>
  </send>

BYE 消息修改

原内容:

  <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>

修改后:

  <send retrans="500">
    <![CDATA[

      BYE [next_url] 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
      [routes]
      Contact: sip:sipp@[local_ip]:[local_port]
      Max-Forwards: 70
      Subject: Performance Test
      Content-Length: 0

    ]]>
  </send>

修改后 uac.xml 完整内容

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">

<!-- This program is free software; you can redistribute it and/or      -->
<!-- modify it under the terms of the GNU General Public License as     -->
<!-- published by the Free Software Foundation; either version 2 of the -->
<!-- License, or (at your option) any later version.                    -->
<!--                                                                    -->
<!-- This program is distributed in the hope that it will be useful,    -->
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of     -->
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the      -->
<!-- GNU General Public License for more details.                       -->
<!--                                                                    -->
<!-- You should have received a copy of the GNU General Public License  -->
<!-- along with this program; if not, write to the                      -->
<!-- Free Software Foundation, Inc.,                                    -->
<!-- 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA             -->
<!--                                                                    -->
<!--                 Sipp default 'uac' scenario.                       -->
<!-- 适配说明:支持经过Kamailio代理转发至FreeSWITCH,主要修改编码、路由记录、消息路由头 -->

<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" rrs="true">
  </recv>

  <!-- Packet lost can be simulated in any send/recv message by         -->
  <!-- by adding the 'lost = "10"'. Value can be [1-100] percent.       -->
  <send>
    <![CDATA[

      ACK [next_url] 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
      [routes]
      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 [next_url] 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
      [routes]
      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>

适配后测试说明

修改完成后,执行压力测试时,需将 stress.sh 中的 FS 变量改为 Kamailio 代理服务器的地址和端口(而非直接指向 FreeSWITCH)。Kamailio 会根据自身配置,将呼叫转发至后端 FreeSWITCH 集群,实现经过代理的 SIP 压力测试。

Doxygen常用注释规则