用 SIPp 给 FreeSWITCH 做测试:注册、呼入、呼出、桥接、会议

Posted on in Tech

Abstract 用 SIPp 给 FreeSWITCH 做测试:注册、呼入、呼出、桥接、会议
Authors Walter Fan
Category Tech
Version v1.0
Updated 2026-11-03
License CC-BY-NC-ND 4.0

大纲

展开看看
  • 一句话:SIPp 是一份 XML 脚本模拟成千上万个话机的 SIP 流量生成器。给 FreeSWITCH 做测试,就是把注册、呼入、呼出、桥接、会议五类场景各写一份脚本压过去。
  • 先搞清角色:SIPp 既能当 UAC(主叫话机)也能当 UAS(被叫服务器)。谁发第一个包,谁就是 UAC。测 FreeSWITCH 时 SIPp 几乎总是 UAC。
  • 三个关键字撑起整套脚本:[call_id]、[service]、[authentication ...]。认证必须两段式——先收 401,再带着摘要重发。
  • 注册:批量注册靠 CSV 注入账号。-r/-rp 控制速率,逐步加压找到 FreeSWITCH 的注册天花板。
  • 呼入(dial in):SIPp 当 UAC 向 FreeSWITCH 发 INVITE,打到 9196 回音或 9664 音乐。带媒体就得 play_pcap_audio 放一段 G.711 PCAP。
  • 呼出(dial out):SIPp 起 UAS 冒充运营商/网关,FreeSWITCH 经 gateway 往外呼,SIPp 收 INVITE 并应答。
  • 桥接(bridge):一个 SIPp 当主叫、另一个 SIPp 当被叫,FreeSWITCH 在中间 bridge。两端媒体都要有声音才算真通。
  • 会议(conference):多路 SIPp 并发打进同一个 conference,验证混音、并发上限和 CPU。
  • 收尾:SIPp 的统计屏和 -trace_err 是第一诊断面;分不清是 SIPp 的锅还是 FreeSWITCH 的锅时,抓包和看 sofia 日志才是终审。

功能写完,单机手工拨一通,echo 听见自己声音——很多人到这就觉得"通了"。可线上从来不是一通一通来的。早高峰几千台话机同一分钟抢注册,座席此起彼伏地拨入拨出,还有会议室里十几路同时混音。手工测试在这种量级面前毫无意义。

你需要的是一个能同时假扮几千台话机的东西,按你编好的剧本自动发 SIP、自动应答、自动统计成功率和时延。SIPp 就是这个东西。

SIPp 的全部语法有自己的 DTD、字段几十个,这里不展开;注册、呼入、呼出、桥接、会议这五类场景,每类一份改掉 IP 就能跑的脚本,再加一张"出问题先看哪儿"的排查清单,够压测用了。

下面的脚本结构参照 SIPp 官方 docs/ 下的示例和 FreeSWITCH 源码树里 src/mod/endpoints/mod_sofia/test/sipp-scenarios/ 的官方测试脚本,命令行参数以 SIPp master 分支为准。FreeSWITCH 配置以默认 vanilla 安装(扩展 1000–1009、密码 1234、回音 9196)为例——这组默认密码只能用在测试机,上线前务必换掉。


先分清 UAC 和 UAS,别一上来就写错脚本

SIPp 不是只会打电话。它能同时扮演两个角色,搞混了脚本就从第一行开始错。

  • UAC(User Agent Client):主动发起的一方,相当于拨号的话机。脚本第一个动作是 <send> 一个 INVITE 或 REGISTER。
  • UAS(User Agent Server):被动应答的一方,相当于接电话的服务器。脚本第一个动作是 <recv> 等着别人发请求。

记一句话就够:谁发第一个包,谁就是 UAC。

测 FreeSWITCH 时,大多数场景 SIPp 都是 UAC——它扮演话机,FreeSWITCH 是被测的服务器。只有一个例外是呼出(dial out):FreeSWITCH 主动往外呼,这时 SIPp 得反过来当 UAS,冒充运营商的网关接住这通呼叫。

脚本里反复出现的几个关键字先认一下,后面不再解释:

关键字 含义
[local_ip] / [local_port] SIPp 自己的地址和端口,由命令行 -i 决定
[remote_ip] / [remote_port] 被测目标(FreeSWITCH)的地址,由命令行末尾参数决定
[service] 被叫号码,命令行 -s 指定,比如 -s 9196
[call_id] SIPp 自动生成的唯一 Call-ID,UAC 模式必须用它
[authentication username=... password=...] 认证摘要占位符,SIPp 收到 401 后自动算出 Authorization 头
[field0] / [field1] 从 CSV 文件注入的第 0、1 列,配合 -inf 使用

场景一:注册(register)——批量话机抢注册

最简单也最常被忽视的压测。几千台话机重启、网络抖动恢复,会在很短时间里涌来一大批 REGISTER。FreeSWITCH 的 Sofia 模块扛不扛得住这个洪峰,手工测不出来。

FreeSWITCH 的注册是带认证的两段式:第一次 REGISTER 不带密码,服务器回 401 Unauthorized 并给一个 nonce;SIPp 拿 nonce 算出摘要,第二次 REGISTER 带上 Authorization 头,服务器才回 200 OK。脚本必须老老实实走这两步,少一步就注册失败。

sequenceDiagram
    participant S as SIPp (UAC)
    participant FS as FreeSWITCH (Sofia)
    S->>FS: REGISTER (无认证, CSeq 1)
    FS-->>S: 401 Unauthorized (WWW-Authenticate: nonce)
    S->>FS: REGISTER (带 Authorization 摘要, CSeq 2)
    FS-->>S: 200 OK (Expires)
    Note over S,FS: 少走第一步, 或 CSeq 不递增 → 注册失败

scenario 文件 register.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="UAC Register with auth">

  <!-- 第一次 REGISTER:不带认证 -->
  <send retrans="500">
    <![CDATA[
      REGISTER sip:[remote_ip]:[remote_port] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
      From: <sip:[field0]@[remote_ip]>;tag=[pid]SIPpTag00[call_number]
      To: <sip:[field0]@[remote_ip]>
      Call-ID: [call_id]
      CSeq: 1 REGISTER
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Max-Forwards: 70
      Expires: 300
      Content-Length: 0
    ]]>
  </send>

  <!-- 服务器要求认证 -->
  <recv response="401" auth="true"/>

  <!-- 第二次 REGISTER:带上摘要,CSeq 要递增 -->
  <send retrans="500">
    <![CDATA[
      REGISTER sip:[remote_ip]:[remote_port] SIP/2.0
      Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
      From: <sip:[field0]@[remote_ip]>;tag=[pid]SIPpTag00[call_number]
      To: <sip:[field0]@[remote_ip]>
      Call-ID: [call_id]
      CSeq: 2 REGISTER
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      [authentication username=[field0] password=[field1]]
      Max-Forwards: 70
      Expires: 300
      Content-Length: 0
    ]]>
  </send>

  <recv response="200"/>

</scenario>

注意两个细节:recv 上的 auth="true" 告诉 SIPp 把收到的 WWW-Authenticate 挑战缓存下来;第二次 send 里的 [authentication ...] 占位符会自动展开成完整的 Authorization 头。两者缺一不可。CSeq 也要从 1 递增到 2,否则 FreeSWITCH 会当成重传。

账号从 CSV 注入 accounts.csv:

SEQUENTIAL
1000;1234
1001;1234
1002;1234
1003;1234
1004;1234
1005;1234
1006;1234
1007;1234
1008;1234
1009;1234

第一行 SEQUENTIAL 是读取顺序(也可以是 RANDOM),后面每行两列对应 [field0](用户名)和 [field1](密码)。

跑起来:

# 每秒 1 个注册,共 10 个,先确认脚本本身是对的
sipp -i 10.0.0.20 -sf register.xml -inf accounts.csv \
     10.0.0.10:5060 -r 1 -rp 1000 -m 10 -aa -trace_err

# 确认无误后加压:每秒 30 个注册
sipp -i 10.0.0.20 -sf register.xml -inf accounts.csv \
     10.0.0.10:5060 -r 30 -rp 1000 -aa -trace_err

-r 30 -rp 1000 表示"每 1000 毫秒发 30 个",也就是 30 次/秒。-aa 让 SIPp 自动忽略 FreeSWITCH 注册后推来的 NOTIFY(否则日志里会刷一堆无关告警)。-trace_err 把错误单独写到一个 _errors.log 文件,方便事后看。

压测的正确姿势是逐步加压:从 -r 1 开始确认流程对,然后 10、30、100……每一档盯着统计屏上的成功率和响应时延,直到 FreeSWITCH 开始丢包或时延飙升。那个拐点就是你这台机器的注册天花板。拿它和业务需求对比,不够就调 Sofia 参数、加内存和 CPU。


场景二:呼入(dial in)——SIPp 拨进来

这是最经典的 UAC 场景:SIPp 扮演话机,向 FreeSWITCH 发 INVITE,打到一个会自动应答的号码。FreeSWITCH vanilla 配置里现成的靶子有两个:9196(回音,把你的声音原样播回)和 9664(放保留音乐)。

sequenceDiagram
    participant S as SIPp (UAC)
    participant FS as FreeSWITCH (echo 9196)
    S->>FS: INVITE (SDP offer)
    FS-->>S: 100 Trying (可选)
    FS-->>S: 180 Ringing (可选)
    FS-->>S: 200 OK (SDP answer)
    S->>FS: ACK
    S-->>FS: RTP (play_pcap_audio)
    FS-->>S: RTP (echo 原样播回)
    Note over S,FS: 不发 RTP → 信令通但"没声音"
    S->>FS: BYE
    FS-->>S: 200 OK

FreeSWITCH 这边不用改——默认 dialplan 里 conf/dialplan/default.xml 已经有这两条:

<extension name="echo">
  <condition field="destination_number" expression="^9196$">
    <action application="answer"/>
    <action application="echo"/>
  </condition>
</extension>

不带媒体的 INVITE(只测信令) uac_invite.xml:

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

  <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:[field0]@[local_ip]:[local_port]>;tag=[pid]SIPpTag01[call_number]
      To: <sip:[service]@[remote_ip]:[remote_port]>
      Call-ID: [call_id]
      CSeq: 1 INVITE
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Max-Forwards: 70
      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 101
      a=rtpmap:0 PCMU/8000
      a=rtpmap:101 telephone-event/8000
    ]]>
  </send>

  <recv response="100" optional="true"/>
  <recv response="180" optional="true"/>
  <recv response="200" rtd="true"/>

  <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:[field0]@[local_ip]:[local_port]>;tag=[pid]SIPpTag01[call_number]
      To: <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
      Call-ID: [call_id]
      CSeq: 1 ACK
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Max-Forwards: 70
      Content-Length: 0
    ]]>
  </send>

  <!-- 通话保持 10 秒 -->
  <pause milliseconds="10000"/>

  <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:[field0]@[local_ip]:[local_port]>;tag=[pid]SIPpTag01[call_number]
      To: <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
      Call-ID: [call_id]
      CSeq: 2 BYE
      Contact: <sip:[field0]@[local_ip]:[local_port]>
      Max-Forwards: 70
      Content-Length: 0
    ]]>
  </send>

  <recv response="200"/>

</scenario>

[peer_tag_param] 是 SIPp 从 200 OK 的 To 头里抓回来的对端 tag——ACK 和 BYE 必须带上它,否则 FreeSWITCH 认不出这是同一个 dialog。

跑起来:

sipp -i 10.0.0.20 -sf uac_invite.xml -inf accounts.csv \
     -s 9196 10.0.0.10:5060 -l 50 -r 10 -rp 1000 -m 500 -trace_err

-l 50 是最大并发 50 路,-m 500 是总共打 500 通。

但只有信令的测试是半成品。 上面这个脚本能跑通 INVITE→200→ACK→BYE,可 RTP 端口其实没发一个包。FreeSWITCH 这边会觉得这通话"没声音"。真要测媒体路径(以及 FreeSWITCH 的转码、录音、媒体超时逻辑),得让 SIPp 真的发 RTP。最省事的做法是放一段预录的 PCAP:

  <!-- 放在 ACK 之后、pause 之前 -->
  <nop>
    <action>
      <exec play_pcap_audio="pcap/g711a.pcap"/>
    </action>
  </nop>
  <pause milliseconds="8000"/>

g711a.pcap 是 SIPp 源码树自带的 G.711 A-law 样本(在 pcap/ 目录下)。注意 SDP 里的 codec 要和 PCAP 对上——G.711 A-law 对应 RTP/AVP 8(PCMA),μ-law 对应 RTP/AVP 0(PCMU)。发 A-law 的 PCAP 却在 SDP 里写 PCMU,FreeSWITCH 会听到一堆噪音。另外用 PCAP 发媒体时 SIPp 通常需要 root 权限(它要直接操作 RTP socket)。


场景三:呼出(dial out)——FreeSWITCH 往外呼

这是唯一一个 SIPp 当 UAS 的场景。现实里 FreeSWITCH 通过 gateway 把电话呼到运营商/上游 SBC,你想在没有真实运营商的情况下测这条路,就让 SIPp 冒充那个上游——起一个 UAS,蹲在某个端口上,接住 FreeSWITCH 发过来的 INVITE 并回 200 OK。

sequenceDiagram
    participant CLI as fs_cli / originate
    participant FS as FreeSWITCH (gateway)
    participant S as SIPp (UAS, 冒充运营商)
    CLI->>FS: originate sofia/gateway/sipp_gw/91234
    FS->>S: INVITE (经 gateway 出局)
    S-->>FS: 180 Ringing
    S-->>FS: 200 OK (SDP answer)
    FS->>S: ACK
    Note over FS,S: 方向反过来: FreeSWITCH 是主叫, SIPp 应答
    FS->>S: BYE
    S-->>FS: 200 OK

FreeSWITCH 这边配一个指向 SIPp 的 gateway(conf/sip_profiles/external/sipp_gw.xml):

<include>
  <gateway name="sipp_gw">
    <param name="proxy" value="10.0.0.20:5070"/>
    <param name="register" value="false"/>
  </gateway>
</include>

再配一条拨号规则,让某个号码走这个 gateway 出去:

<extension name="dial_out_to_sipp">
  <condition field="destination_number" expression="^(9[0-9]{3})$">
    <action application="bridge" data="sofia/gateway/sipp_gw/$1"/>
  </condition>
</extension>

SIPp 这边起一个 UAS uas.xml:

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

  <recv request="INVITE"/>

  <send>
    <![CDATA[
      SIP/2.0 180 Ringing
      [last_Via:]
      [last_From:]
      [last_To:];tag=[pid]SIPpTag02[call_number]
      [last_Call-ID:]
      [last_CSeq:]
      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
      Content-Length: 0
    ]]>
  </send>

  <send retrans="500">
    <![CDATA[
      SIP/2.0 200 OK
      [last_Via:]
      [last_From:]
      [last_To:];tag=[pid]SIPpTag02[call_number]
      [last_Call-ID:]
      [last_CSeq:]
      Contact: <sip:[local_ip]:[local_port];transport=[transport]>
      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 101
      a=rtpmap:0 PCMU/8000
      a=rtpmap:101 telephone-event/8000
    ]]>
  </send>

  <recv request="ACK" rtd="true"/>

  <recv request="BYE"/>

  <send>
    <![CDATA[
      SIP/2.0 200 OK
      [last_Via:]
      [last_From:]
      [last_To:]
      [last_Call-ID:]
      [last_CSeq:]
      Content-Length: 0
    ]]>
  </send>

</scenario>

UAS 脚本里几乎所有头都用 [last_...] ——这是把收到的请求里的对应头原样回贴,这样 Via/From/Call-ID 自然对得上,不用自己拼。

先起 SIPp(它是被叫,得先就位),再从 FreeSWITCH 发起呼叫:

# 终端 1:SIPp 当 UAS 蹲守 5070 端口
sipp -i 10.0.0.20 -p 5070 -sf uas.xml -trace_err
# 终端 2:在 fs_cli 里发起一通外呼,destination 匹配上面那条规则
freeswitch@internal> originate sofia/gateway/sipp_gw/91234 &park

SIPp 的统计屏上出现一通被接听的呼叫,就说明 FreeSWITCH 的外呼链路(gateway 选路、SDP 协商、ACK 处理)是通的。要压测就把 originate 换成一个循环脚本,或者用 FreeSWITCH 的 fs_cli 批量发起。


场景四:桥接(bridge)——一进一出,FreeSWITCH 居中

前面三个场景,SIPp 要么只对着 FreeSWITCH 的内置应用(echo),要么单独测一个方向。但真实话务的核心是 A 打给 B,FreeSWITCH 把两条腿桥在一起。这个场景必须同时起两个 SIPp:一个当主叫(UAC),一个当被叫(UAS),FreeSWITCH 在中间做 bridge。

sequenceDiagram
    participant A as SIPp 主叫 (UAC)
    participant FS as FreeSWITCH (bridge)
    participant B as SIPp 被叫 (UAS)
    A->>FS: INVITE (拨 2000)
    FS->>B: INVITE (bridge 出第二条腿)
    B-->>FS: 200 OK
    FS-->>A: 200 OK
    A->>FS: ACK
    FS->>B: ACK
    A-->>FS: RTP 媒体
    FS-->>B: RTP 媒体
    B-->>FS: RTP 媒体
    FS-->>A: RTP 媒体
    Note over A,B: 两端都要放 PCAP, 双向都有声音才算真桥通
    A->>FS: BYE
    FS->>B: BYE

FreeSWITCH dialplan:让主叫拨某个号码时,桥接到被叫所在的 SIPp(conf/dialplan/default.xml):

<extension name="bridge_to_callee">
  <condition field="destination_number" expression="^(2000)$">
    <action application="bridge" data="sofia/external/2000@10.0.0.21:5080"/>
  </condition>
</extension>

这里 10.0.0.21:5080 是被叫那个 SIPp UAS 的地址。

三方的启动顺序(被叫先就位,主叫最后发起):

# 终端 1:被叫侧 SIPp(UAS),蹲在 5080,收 INVITE 就应答并放 PCAP
sudo sipp -i 10.0.0.21 -p 5080 -sf uas_media.xml -trace_err
# 终端 2:主叫侧 SIPp(UAC),拨 2000,FreeSWITCH 会把它桥到被叫
sudo sipp -i 10.0.0.20 -sf uac_invite.xml -inf accounts.csv \
     -s 2000 10.0.0.10:5060 -l 50 -r 10 -rp 1000 -m 500 -trace_err

其中 uas_media.xml 就是场景三的 uas.xml 再加一段 play_pcap_audio(应答后放 PCAP),让被叫侧也真的发 RTP。

桥接测试的关键在"双向都要有声音"。 只看 SIP 信令通过(两边都 200 OK)是不够的:FreeSWITCH 的 bridge 本质是把两条腿的 RTP 对接起来,只有两端 SIPp 都在发 PCAP 媒体流、而且在各自的统计里看到收到了对端的 RTP,这通桥接才算真通。很多人卡在这:信令全绿,但一端没放媒体,结果是"接通了但一方没声音"——这正是 bridge 测试要抓的 bug。加压时盯住 FreeSWITCH 的 CPU 和 RTP 端口范围(rtp-start-port/rtp-end-port),桥接是双倍 RTP,最容易先把媒体端口或 CPU 吃满。


场景五:会议(conference)——多路并发混音

会议是 bridge 的放大版:不是两条腿对接,而是 N 条腿进同一个房间混音。测的是 FreeSWITCH 的 mod_conference 在并发下的混音开销和人数上限。

sequenceDiagram
    participant S1 as SIPp 腿 1
    participant S2 as SIPp 腿 2
    participant SN as SIPp 腿 N
    participant FS as FreeSWITCH (conference 3000)
    S1->>FS: INVITE → 进会议室
    S2->>FS: INVITE → 进会议室
    SN->>FS: INVITE → 进会议室
    FS-->>S1: 200 OK / ACK
    FS-->>S2: 200 OK / ACK
    FS-->>SN: 200 OK / ACK
    par 每条腿都发 RTP
        S1-->>FS: RTP
        S2-->>FS: RTP
        SN-->>FS: RTP
    end
    FS-->>S1: 混音后 RTP
    FS-->>S2: 混音后 RTP
    FS-->>SN: 混音后 RTP
    Note over S1,FS: -d 保持 60s 让 N 路同时在线; 不发 RTP 则无混音负载

FreeSWITCH dialplan(vanilla 默认就有类似的,拨 3000 进会议室):

<extension name="conference">
  <condition field="destination_number" expression="^(3000)$">
    <action application="answer"/>
    <action application="conference" data="$1@default"/>
  </condition>
</extension>

SIPp 这边直接复用场景二带 PCAP 的呼入脚本,把被叫号码指向会议室,并发数开大:

sudo sipp -i 10.0.0.20 -sf uac_invite_media.xml -inf accounts.csv \
     -s 3000 10.0.0.10:5060 -l 20 -r 2 -rp 1000 -m 20 -d 60000 -trace_err

几个参数和前面不一样:

  • -l 20 并发 20 路——会议靠的是并发,不是呼叫速率,所以这里要的是同时在线 20 路,而不是每秒打多少。
  • -d 60000 让每通呼叫在 INVITE 和 BYE 之间停 60 秒,保证这 20 路同时待在会议室里混音,而不是打进来就挂。
  • 每一路都要 play_pcap_audio 放媒体,否则会议室里是 20 个哑巴,mod_conference 根本没有混音负载,压不出真实开销。

压测时盯三样:FreeSWITCH 的 CPU(混音是纯计算,人越多越吃 CPU)、conference list 里的实际人数(对不对得上你发起的并发)、以及有没有人因为超时被踢。逐步把 -l 从 20 加到 50、100,找到单会议室的人数拐点。


出问题先看哪儿:SIPp × FreeSWITCH 排查清单

压测跑红了,第一反应往往是"FreeSWITCH 不行"。但很多时候是脚本写错或 SIPp 配置不对。按这个顺序查,能省掉大半冤枉路:

症状 大概率原因 先看哪儿
注册全部失败,连 401 都没有 SIPp 发不出包/IP 端口不对 -trace_err 日志、-i 地址对不对
收到 401 但拿不到 200 认证两段式没写对,或密码错 recv 上有没有 auth="true"、CSeq 有没有递增
INVITE 收到 403/407 FreeSWITCH 要求认证但脚本没带 profile 的 auth-calls、脚本是否走认证
信令全通但"没声音" 根本没发 RTP 脚本里有没有 play_pcap_audio
有 RTP 但对端听着是噪音 codec 和 PCAP 对不上 SDP 里的 PCMA/PCMU 和 PCAP 一致吗
并发一高就大量超时/丢包 到了 FreeSWITCH 或机器的真实上限 FreeSWITCH CPU、RTP 端口范围、Sofia 参数
SIPp 报 RTP 相关权限错误 放 PCAP 需要 root 用 sudo 跑

两个终审工具:SIPp 的统计屏(按 1–9 切换不同视图,看成功/失败计数和响应时延分布)和 FreeSWITCH 的 sofia 日志(fs_cli 里 sofia global siptrace on,或直接 sofia loglevel all 9)。分不清是谁的锅时,两边同时抓包(SIPp 侧和 FreeSWITCH 侧各 tcpdump 一份),用 Wireshark 的 SIP/RTP 流视图对一下,包到底卡在哪一跳一目了然。


总结:先证明脚本对,再逐步加压找拐点

用 SIPp 测 FreeSWITCH,难的从来不是某个单独的 XML,而是三件事:分清 SIPp 当 UAC 还是 UAS、把认证两段式写对、以及记得真的发 RTP 媒体。这三样踩过一遍,五类场景的脚本结构其实高度相似,改改号码和并发参数就能复用。

落地就两步,顺序别反:

  1. 先用 -r 1 -m 10 把脚本跑通,确认流程对、认证过、媒体有声音。脚本不对就加压,是在用错误的子弹打靶。
  2. 再逐步加压找拐点,每一档盯住统计屏的成功率和时延,直到 FreeSWITCH 开始丢包。那个拐点就是这台机器在这个场景下的真实容量——拿它和业务需求对比,才知道要不要调参、加机器。

手工拨通一通,只证明"能通";SIPp 压出拐点,才知道"能扛多少"。 后者才是上线前真正要回答的问题。

参考与延伸

SIPp 本体

  • SIPp 官方参考文档:命令行参数、关键字、actions、PCAP Play、统计屏的权威出处。本文的 [authentication]、[last_*]、play_pcap_audio 用法都以此为准。
  • SIPp 源码仓库:docs/ 目录下有 uac.xml、uac_pcap.xml、uas.xml 等内置场景的完整 XML,是自己写脚本最好的模板;pcap/ 下有现成的 g711a.pcap 媒体样本。
  • sipp -sd uac:把内置场景直接导出成 XML,改一改就能用,比从空白文件开始快得多。

FreeSWITCH 侧

上手教程与现成脚本

配套诊断工具

  • Wireshark:SIP/RTP 流视图(Telephony → VoIP Calls / RTP Streams)是定位"卡在哪一跳"的终审工具,两边同时抓包对比最有效。
  • sngrep:终端里实时看 SIP 对话的轻量工具,压测时比翻日志快。

全文思维导图

@startmindmap
<style>
mindmapDiagram {
  node {
    BackgroundColor #F8F9FA
    RoundCorner 10
    Padding 10
    FontSize 13
  }
  :depth(0) {
    BackgroundColor #1E3A5F
    FontColor white
    FontSize 18
    FontStyle bold
  }
  :depth(1) {
    FontSize 15
    FontStyle bold
  }
  :depth(2) {
    FontSize 13
  }
}
</style>

* SIPp 测 FreeSWITCH
** 基础概念
*** UAC = 发第一个包
*** UAS = 等着收包
*** 认证两段式
** 注册 register
*** 401 → 带摘要重发
*** CSV 注入账号
*** -r/-rp 逐步加压
** 呼入 dial in
*** SIPp 当 UAC
*** 打 9196 回音
*** play_pcap_audio 发媒体
** 呼出 dial out
*** SIPp 当 UAS
*** 冒充运营商网关
*** gateway + bridge
** 桥接 bridge
*** 两个 SIPp
*** 双向都要有声音
*** 盯 RTP 端口/CPU
** 会议 conference
*** 多路并发
*** -l 控并发 -d 保持
*** 盯混音 CPU
** 排查
*** 统计屏 + trace_err
*** sofia 日志
*** 两边抓包
@endmindmap

用 SIPp 给 FreeSWITCH 做测试 - 思维导图


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。 欢迎在我的个人网站 https://www.fanyamin.com 访问原文并评论。

相关文章