iperf 详细使用说明书
**版本**: 2.0.5 | **许可**: NLANR/DAST (University of Illinois NCSA) | **官网**: http://iperf.sourceforge.net/ **原作者**: Mark Gates, Alex Warshavsky | **维护者**: Jon Dugan
1. 概述
1.1 什么是 Iperf
Iperf 是一个网络带宽测量工具,用于测试 TCP 和 UDP 的吞吐量。它采用经典的客户端-服务器架构:
- 服务器端 (
iperf -s):监听端口,丢弃或接收流量 - 客户端 (
iperf -c <host>):生成流量,向服务器发送数据
1.2 核心能力
| 特性 | 说明 |
|---|---|
| TCP 吞吐量测试 | 测量 TCP 带宽,支持窗口大小调优 |
| UDP 吞吐量测试 | 测量 UDP 带宽,支持抖动和丢包率统计 |
| 多线程并行 | `-P` 参数支持多流并发测试 |
| 双向测试 | `-d` (同时双向) 和 `-r` (交替双向) |
| IPv4/IPv6 | 支持双栈协议 |
| 多播 | 支持 IPv4/IPv6 组播测试 |
| 多种报告格式 | 默认文本格式和 CSV 格式 |
| 跨平台 | Linux, Unix, Windows |
1.3 三线程架构
iperf 采用独特的三线程模型:
main() 启动
│
├── Listener 线程 ── 接受连接,生成 Server 线程
├── Client/Server 线程 ── 执行数据传输
└── Reporter 线程 ── 收集统计信息,生成报告
Reporter 通过 ring buffer 与传输线程通信,采用生产者-消费者模式:Client/Server 生产数据包记录,Reporter 消费并聚合。
2. 目录结构
iperf-2.0.5/
├── README # 简要构建与使用说明
├── autogen.sh # 构建系统再生脚本
├── configure.ac # Autoconf 输入文件
├── Makefile.am / Makefile.in # Automake 输入文件
│
├── src/ # 核心源代码
│ ├── main.cpp # 入口点,信号处理,线程编排
│ ├── Client.cpp # TCP/UDP 客户端实现
│ ├── Server.cpp # 服务器接收/发送实现
│ ├── Listener.cpp # 监听、连接接受、守护进程
│ ├── Settings.cpp # 所有 CLI 选项解析
│ ├── PerfSocket.cpp # 套接字选项设置(窗口/MSS/NoDelay/TOS)
│ ├── Launch.cpp # C 到 C++ 的线程启动桥接
│ ├── List.cpp # 客户端地址链表管理
│ ├── Locale.c # 所有本地化字符串(帮助/报告/警告)
│ ├── Reporter.c # 报告系统核心(ring buffer、聚合)
│ ├── ReportDefault.c # 人类可读文本报告
│ ├── ReportCSV.c # CSV 格式报告
│ ├── Extractor.c # 从文件读取数据(-F 选项)
│ ├── sockets.c # readn/writen 包装器、TCP MSS
│ ├── SocketAddr.c # DNS 解析、地址操作
│ ├── stdio.c # K/M/G 后缀解析、字节格式化
│ ├── tcp_window_size.c # TCP 缓冲区大小设置/查询
│ ├── gnu_getopt.c # GNU getopt 长选项解析
│ ├── gnu_getopt_long.c # getopt_long 实现
│ ├── service.c # Windows 服务集成
│ └── Makefile.am # 源文件编译规则
│
├── include/ # 头文件(28 个)
│ ├── Settings.hpp # thread_Settings 结构体 + 标志位宏
│ ├── Thread.h # 线程抽象层定义
│ ├── Reporter.h # 报告系统数据结构
│ ├── Client.hpp # Client 类声明
│ ├── Server.hpp # Server 类声明
│ ├── Listener.hpp # Listener 类声明
│ ├── PerfSocket.hpp # SetSocketOptions 声明
│ ├── Timestamp.hpp # 时间戳工具
│ ├── Condition.h # 条件变量抽象
│ ├── Mutex.h # 互斥锁抽象
│ ├── SocketAddr.h # 地址操作声明
│ ├── Extractor.h # 文件数据提取器
│ ├── List.h # 链表管理
│ ├── Locale.h # 本地化字符串 extern
│ ├── version.h # 版本号
│ ├── headers.h # 平台抽象中枢
│ ├── report_default.h / report_CSV.h # 报告函数声明
│ ├── gnu_getopt.h # getopt 声明
│ ├── service.h # Windows 服务声明
│ ├── util.h # 工具宏
│ └── delay.hpp # 微秒延迟
│
├── compat/ # 平台兼容层(9 个源文件)
│ ├── Thread.c # 线程子系统实现(POSIX/Win32/单线程)
│ ├── delay.cpp # 高精度微秒延迟(nanosleep)
│ ├── signal.c # 跨平台信号处理(Unix sigaction / Win32 ConsoleControlHandler)
│ ├── gettimeofday.c # Win32 gettimeofday 实现
│ ├── inet_ntop.c # Win32 inet_ntop 实现
│ ├── inet_pton.c # Win32 inet_pton 实现
│ ├── snprintf.c # C99 snprintf 兼容
│ └── headers_slim.h # 轻量平台头文件
│
├── doc/ # 文档
│ ├── index.html # 用户手册 HTML
│ ├── ui_license.html # 许可
│ └── dast.gif # DAST 标志
│
├── man/ # 手册页
│ └── iperf.1 # Man page
│
└── m4/ # Autoconf 宏
├── acx_pthread.m4 # POSIX 线程检测
├── ax_create_stdint_h.m4 # stdint.h 生成
└── dast.m4 # DAST 工具宏(accept 参数检测)
3. 下载途径
3.1 官方源码下载
Iperf 官方发布地址为 SourceForge:
# 下载最新版本 (替换版本号)
wget https://sourceforge.net/projects/iperf2/files/iperf-2.0.5.tar.gz
# 历史版本示例
wget https://sourceforge.net/projects/iperf2/files/iperf-2.0.4.tar.gz
3.2 Git 仓库
# SourceForge Git
git clone https://git.code.sf.net/p/iperf2/code iperf2-code
# GitHub 镜像
git clone https://github.com/esnet/iperf.git
3.3 YUM / DNF 安装 (RHEL/CentOS/Fedora)
# EPEL 仓库中的 iperf
yum install iperf -y # CentOS/RHEL 7
dnf install iperf -y # CentOS/RHEL 8+ / Fedora
3.4 APT 安装 (Debian/Ubuntu)
apt-get install iperf -y
3.5 本地源码包📁 本地下载
提示:点击按钮将打开网络文件夹,点击即可下载
本目录提供 iperf 源码包及 RPM 包,可直接使用:
| 文件 | 版本 | 格式 |
|---|---|---|
iperf-2.0.5.tar.gz | 2.0.5 | gzip |
iperf3-3.1.3-1.fc24.x86_64.rpm | 3.1.3 | RPM |
4. 安装指南
4.1 系统要求
- C++ 编译器(g++ 或兼容)
- POSIX 线程库(pthread)或 Win32 线程
- GNU Autotools(autoconf >= 2.59, automake)
4.2 从源码编译(Linux)
# 1. 进入源码目录
cd iperf-2.0.5
# 2. 配置(自动检测系统特性)
./configure
# 常用 configure 选项:
# --disable-ipv6 禁用 IPv6 支持
# --disable-multicast 禁用多播支持
# --disable-threads 禁用多线程(单线程模式)
# --enable-debuginfo 启用调试信息
# --disable-web100 禁用 Web100 支持
# 3. 编译
make
# 4. 安装(需要 root 权限)
sudo make install
4.3 configure 检测流程
configure.ac 控制整个自动检测过程:
1. 编译器检测 —
AC_PROG_CXX, AC_PROG_CC(去除隐式 -g 标志)
2. 线程库检测 —
ACX_PTHREAD() 检测 POSIX 线程,定义 HAVE_POSIX_THREAD
3. 网络库检测 — 检测
-lnsl(gethostbyname)和 -lsocket(socket)
4. 头文件检测 — 检测
arpa/inet.h, netdb.h, netinet/in.h, sys/socket.h 等
5. accept() 参数类型 — 用
DAST_ACCEPT_ARG 测试 socklen_t/int/size_t
6. IPv6 支持 — 检测
sockaddr_storage, sockaddr_in6, AF_INET6
7. 多播支持 — 检测
ip_mreq, IP_ADD_MEMBERSHIP, IPv6 多播
8. printf 64位支持 — 测试
%lld 和 %qd 格式,定义 HAVE_QUAD_SUPPORT
9. GNU Make 检测 — 使用
$(strip ...) 优化编译行
4.4 autogen.sh 详解
autogen.sh 用于从 configure.ac 重新生成构建系统:
#!/bin/sh
# 收集 aclocal 宏目录
SYS_ACLOCAL_DIR=`aclocal --print-ac-dir`
for i in m4 /usr/local/share/aclocal; do
if [ ! $i = $SYS_ACLOCAL_DIR -a -d $i ]; then
ACLOCAL_OPTS="$ACLOCAL_OPTS -I $i"
fi
done
aclocal $ACLOCAL_OPTS # 收集 autoconf 宏
autoheader # 生成 config.h.in
autoconf # 生成 configure 脚本
automake --add-missing --include-deps --foreign # 生成 Makefile.in
4.5 编译产物
编译后 src/ 目录下的关键文件:
| 文件 | 说明 |
|---|---|
| `iperf` | 可执行二进制文件 |
| `*.o` | 各源文件的目标文件 |
| `.deps/*.Po` | 依赖关系文件(自动生成) |
| `compat/libcompat.a` | 兼容层静态库 |
5. 快速开始
5.1 基本 TCP 测试
服务器端(目标机器):
iperf -s
输出:
------------------------------------------------------------
Server listening on TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
客户端(发起测试的机器):
iperf -c <服务器IP地址>
输出:
------------------------------------------------------------
Client connecting to 192.168.1.100, TCP port 5001
TCP window size: 85.3 KByte (default)
------------------------------------------------------------
[ 3] local 192.168.1.200 port 54321 connected with 192.168.1.100 port 5001
[ ID] Interval Transfer Bandwidth
[ 3] 0.0-10.0 sec 1.10 GBytes 940 Mbits/sec
5.2 基本 UDP 测试
# 服务器端
iperf -s -u
# 客户端(默认 1 Mbit/s)
iperf -c <服务器IP> -u
# 客户端(指定带宽 100 Mbit/s)
iperf -c <服务器IP> -u -b 100M
5.3 常用参数速查表
| 参数 | 说明 | 示例 |
|---|---|---|
| `-s` | 服务器模式 | `iperf -s` |
| `-c <host>` | 客户端模式 | `iperf -c 10.0.0.1` |
| `-u` | UDP 测试 | `iperf -c 10.0.0.1 -u` |
| `-p <port>` | 指定端口(默认5001) | `iperf -s -p 8080` |
| `-P <n>` | 并行流数 | `iperf -c 10.0.0.1 -P 10` |
| `-t <n>` | 测试时长(秒,默认10) | `iperf -c 10.0.0.1 -t 60` |
| `-i <n>` | 报告间隔(秒) | `iperf -c 10.0.0.1 -i 3` |
| `-b <n>` | UDP 目标带宽 | `iperf -c 10.0.0.1 -u -b 1000M` |
| `-w <n>` | TCP 窗口大小 | `iperf -c 10.0.0.1 -w 256K` |
| `-l <n>` | 缓冲区长度 | `iperf -c 10.0.0.1 -l 64K` |
| `-d` | 同时双向测试 | `iperf -c 10.0.0.1 -d` |
| `-r` | 交替双向测试 | `iperf -c 10.0.0.1 -r` |
| `-f <fmt>` | 格式 K/M/G (bits/bytes) | `iperf -c 10.0.0.1 -f M` |
| `-B <host>` | 绑定地址/接口 | `iperf -s -B 10.0.0.1` |
| `-V` | IPv6 模式 | `iperf -s -V` |
| `-y C` | CSV 输出格式 | `iperf -c 10.0.0.1 -y C` |
6. 命令行选项完整参考
6.1 通用选项
| 短选项 | 长选项 | 参数 | 说明 |
|---|---|---|---|
| `-f` | `--format` | `[kmKM]` | 报告格式:K=Kbits, M=Mbits, K=KBytes, M=MBytes |
| `-h` | `--help` | 无 | 打印帮助信息 |
| `-i` | `--interval` | `#` | 周期性带宽报告的间隔秒数 |
| `-l` | `--len` | `#[KM]` | 读写缓冲区长度(默认 8KB,实际 iperf 2.0.5 默认 128KB) |
| `-m` | `--print_mss` | 无 | 打印 TCP MSS 和 MTU 信息 |
| `-o` | `--output` | `<filename>` | 将报告输出到指定文件 |
| `-p` | `--port` | `#` | 服务器监听/客户端连接端口(默认 5001) |
| `-u` | `--udp` | 无 | 使用 UDP 代替 TCP |
| `-w` | `--window` | `#[KM]` | TCP 窗口大小(socket 缓冲区大小) |
| `-B` | `--bind` | `<host>` | 绑定到指定主机(接口或多播地址) |
| `-C` | `--compatibility` | 无 | 兼容旧版本,不发送额外消息 |
| `-M` | `--mss` | `#` | TCP 最大分段大小(MTU - 40 字节) |
| `-N` | `--nodelay` | 无 | 设置 TCP No Delay,禁用 Nagle 算法 |
| `-v` | `--version` | 无 | 打印版本信息并退出 |
| `-V` | `--IPv6Version` | 无 | 设置域为 IPv6 |
| `-x` | `--reportexclude` | `[CDMSV]` | 排除报告:C(连接) D(数据) M(多播) S(设置) V(服务器) |
| `-y` | `--reportstyle` | `C` | 报告格式:C 或 c 表示 CSV(逗号分隔) |
6.2 服务器专用选项
| 短选项 | 长选项 | 说明 |
|---|---|---|
| `-s` | `--server` | 以服务器模式运行 |
| `-U` | `--single_udp` | 以单线程 UDP 模式运行(兼容某些平台) |
| `-D` | `--daemon` | 以守护进程模式运行服务器 |
6.3 客户端专用选项
| 短选项 | 长选项 | 参数 | 说明 |
|---|---|---|---|
| `-b` | `--bandwidth` | `#[KM]` | UDP 目标带宽 bits/sec(默认 1Mbit/s,隐含 `-u`) |
| `-c` | `--client` | `<host>` | 以客户端模式运行,连接到 `<host>` |
| `-d` | `--dualtest` | 无 | 同时双向测试(客户端和服务端同时发送) |
| `-n` | `--num` | `#[KM]` | 传输字节数(替代 `-t` 定时) |
| `-r` | `--tradeoff` | 无 | 交替双向测试(客户端先发送,然后服务端发送) |
| `-t` | `--time` | `#` | 传输持续时间秒数(默认 10 秒) |
| `-F` | `--fileinput` | `<name>` | 从文件读取要传输的数据 |
| `-I` | `--stdin` | 无 | 从标准输入读取要传输的数据 |
| `-L` | `--listenport` | `#` | 双向测试的接收端口 |
| `-P` | `--parallel` | `#` | 并行客户端线程数 |
| `-T` | `--ttl` | `#` | 多播 TTL(默认 1) |
| `-Z` | `--linux-congestion` | `<algo>` | TCP 拥塞控制算法(仅 Linux) |
6.4 环境变量
TCP_WINDOW_SIZE— 设置 TCP 窗口/缓冲区大小IPERF_<长选项名>— 大多数选项可通过环境变量设置,如IPERF_BANDWIDTH=100M
6.5 报告排除选项详解 (`-x`)
-x 参数接受以下字符组合:
| 字符 | 排除的报告类型 | 对应标志位 |
|---|---|---|
| `C` | 连接报告 | `FLAG_NOCONNREPORT` |
| `D` | 数据传输报告 | `FLAG_NODATAREPORT` |
| `M` | 多播报告 | `FLAG_NOMULTREPORT` |
| `S` | 设置报告 | `FLAG_NOSETTREPORT` |
| `V` | 服务器统计报告 | `FLAG_NOSERVREPORT` |
7. 源代码架构
7.1 整体设计
Iperf 是一个 C/C++ 混合项目。核心网络类(Client, Server, Listener)使用 C++,而报告系统、线程管理、系统兼容层使用纯 C,以 extern "C" 实现互操作。
- 所有运行状态存储在
thread_Settings结构体中,以便该结构体可以跨 C/C++ 边界传递 - 不使用 C++
bool类型 — 改用 32 位 bitmaskflags字段(28 个布尔标志) - 线程子系统提供统一接口,在 POSIX 线程 / Win32 线程 / 单线程之间透明切换
设计约束:
7.2 线程模型
main()
│
├── thread_start(reporter)
│ └── reporter_spawn() → 无限循环处理 ReportRoot 链表
│
├── [如果是客户端] client_init()
│ ├── Settings_GenerateListenerSettings() [用于 -d/-r]
│ ├── InitMulti() [多流聚合]
│ └── 为每个 -P 线程复制 Settings
│
└── thread_start(client_or_listener)
│
└── thread_run_wrapper()
│
├── kMode_Listener → listener_spawn() → Listener::Run()
│ └── accept() 循环 → server_spawn() 每连接
├── kMode_Server → server_spawn() → Server::Run()
├── kMode_Client → client_spawn() → Client::Run()
└── kMode_Reporter → reporter_spawn()
7.3 报告系统(Reporter)
Reporter 是 iperf 最精巧的部分,采用 ring buffer + 链表 的设计:
传输线程(Client/Server) Reporter 线程
│ │
├── InitReport() → 创建 ReportHeader │
│ 插入 ReportRoot 链表 │
│ │
├── ReportPacket() → 写入 ring buffer │
│ (agentindex++) │
│ ├── reporter_spawn() 循环
│ │ ├── 等待 ReportCond
│ │ ├── reporter_process_report()
│ │ │ ├── reporter_handle_packet()
│ │ │ │ ├── 累加字节/包数
│ │ │ │ ├── 计算抖动 (RFC 1889)
│ │ │ │ ├── 检测丢包/乱序
│ │ │ │ └── reporter_condprintstats()
│ │ │ └── 聚合多流 → reporter_handle_multiple_reports()
│ │ └── 调度 reporter_print() →
│ │ ReportDefault.c 或 ReportCSV.c
│ │
├── CloseReport() → 发送终止信号 │
│ (PacketID = -1) │
│ │
└── EndReport() → agentindex = -1 └── 释放 ReportHeader
- 每个流对应一个
Transfer_Infoslot reporter_handle_multiple_reports()按 startTime 匹配同一轮的 slot- 当
free计数达到mThreads时,触发[SUM]报告打印
多流聚合 (
-P 10):
7.4 平台抽象层
compat/ 目录提供跨平台兼容:
| 层级 | POSIX (Linux/Unix) | Win32 |
|---|---|---|
| 线程 | `pthread_create` / `pthread_t` | `CreateThread` / `HANDLE` + `DWORD` |
| 信号 | `sigaction()` | `SetConsoleCtrlHandler()` + 自定义分发器 |
| 时间 | 原生 `gettimeofday()` | 兼容实现 `compat/gettimeofday.c` |
| 地址转换 | 原生 `inet_pton`/`inet_ntop` | 兼容实现 |
| 服务 | 无 | `service.c`(Windows SCM 集成) |
| 网络 | 统一 `readn`/`writen` 包装器(Stevens 风格) |
7.5 协议头格式
client_hdr(客户端→服务器,协商参数):
typedef struct client_hdr {
int32_t flags; // HEADER_VERSION1 (0x80000000) 表示版本1
int32_t numThreads; // 并行线程数
int32_t mPort; // 回连端口(双向测试)
int32_t bufferlen; // 缓冲区大小
int32_t mWinBand; // 窗口/带宽
int32_t mAmount; // 数据量/时长
} client_hdr;
server_hdr(服务器→客户端,UDP 统计):
typedef struct server_hdr {
int32_t flags;
int32_t total_len1, total_len2; // 64 位总长度
int32_t stop_sec, stop_usec; // 结束时间
int32_t error_cnt; // 丢包数
int32_t outorder_cnt; // 乱序包数
int32_t datagrams; // 总数据报数
int32_t jitter1, jitter2; // 抖动值(整数+小数部分)
} server_hdr;
UDP_datagram(UDP 数据报头,12 字节):
typedef struct UDP_datagram {
int32_t id; // 包序号
u_int32_t tv_sec; // 发送时间戳(秒)
u_int32_t tv_usec; // 发送时间戳(微秒)
} UDP_datagram;
8. 关键源文件详解
7.1 main.cpp — 程序入口点
文件: src/main.cpp (298 行)
- 全局变量定义:
sInterupted(中断标志)、groupID(多流组 ID)、ReportCond/ReportDoneCond(报告同步条件变量) Sig_Interupt():线程安全中断处理,两次 Ctrl-C 强制退出main()流程:
功能:
1.
my_signal() 安装 SIGTERM/SIGINT 处理器
2.
Settings_Initialize() → Settings_ParseCommandLine() 解析参数
3.
thread_init() 初始化线程子系统
4. 创建 Reporter 线程 (
thread_start(reporter))
5. 客户端:
client_init() + 启动客户/监听线程
6. 服务端:启动监听线程
7.
thread_joinall() 等待所有线程完成
8.
thread_destroy() 清理
关键代码:
int main( int argc, char **argv ) {
my_signal( SIGTERM, Sig_Interupt );
my_signal( SIGINT, Sig_Interupt );
Settings_Initialize( &mSettings );
Settings_ParseCommandLine( argc, argv, &mSettings );
thread_init();
// 启动 reporter 线程
if (mSettings.mThreadMode == kMode_Client) {
client_init(&mSettings);
}
thread_start(&mSettings);
thread_joinall();
thread_destroy();
return 0;
}
7.2 Settings.cpp — 命令行选项解析
文件: src/Settings.cpp (844 行)
Settings_Initialize():设置所有默认值(mPort=5001,mBufLen=128K,mAmount=1000(10 秒),kDefault_UDPRate=1Mbit/s)Settings_ParseCommandLine():使用gnu_getopt_long()解析 37 个 CLI 选项Settings_Interpret():400+ 行的 switch 语句处理每个选项Settings_GenerateClientSettings():服务端从client_hdr创建反向客户端(用于双向测试)Settings_ParseEnvironment():从环境变量读取设置(IPERF_<OPTION>格式)
功能:
标志位系统:使用单个 32 位 int flags 字段管理 28 个布尔选项,通过位掩码宏操作:
#define FLAG_UDP 0x00000800
#define isUDP(settings) ((settings->flags & FLAG_UDP) != 0)
#define setUDP(settings) settings->flags |= FLAG_UDP
#define unsetUDP(settings) settings->flags &= ~FLAG_UDP
7.3 Client.cpp — 客户端实现
文件: src/Client.cpp (471 行)
Client::Connect():socket() → SetSocketOptions() → bind() → connect()Client::RunTCP():TCP 模式 — 使用setitimer定时 + 写循环 + 带宽跟踪Client::RunUDP():UDP 模式 — 基于延迟的带宽限制 + 序列号 + 时间戳Client::InitiateServer():向服务器发送client_hdr协商参数Client::write_UDP_FIN():UDP 结束信号,最多重试 10 次(250ms 超时)
功能:
TCP 写循环核心逻辑:
void Client::RunTCP() {
struct itimerval it;
it.it_value.tv_sec = mSettings->mAmount / 100;
setitimer(ITIMER_REAL, &it, NULL);
// 循环写入直到信号中断
do {
writen(mSettings->mSock, mBuf, mSettings->mBufLen);
ReportPacket(reporthdr, &packet);
} while (!sInterupted);
}
7.4 Server.cpp — 服务器实现
文件: src/Server.cpp (249 行)
Server::Run():接收循环(TCPreadn/ UDPrecv)- UDP 包 ID 跟踪:检测丢包(
cntError)和乱序(cntOutofOrder) - 终止条件:收到
PacketID < 0的结束信号 Server::write_UDP_AckFIN():发送 ACK FIN +server_hdr(包含服务器端统计)
功能:
7.5 Listener.cpp — 监听器实现
文件: src/Listener.cpp (717 行)
Listener::Listen():socket() → setsockopt(SO_REUSEADDR) → bind() → listen(5)Listener::Run():主 accept 循环 — TCP 每连接生成线程,UDP 单/多服务器模式Listener::Accept():TCPaccept()+ EINTR 处理,UDPrecvfrom()+connect()回连Listener::runAsDaemon():双 fork 守护进程化(仅 Unix)Listener::UDPSingleServer():单线程 UDP 模式(Win32/Solaris 兼容)- 多播加入:
setsockopt(IP_ADD_MEMBERSHIP)或IPV6_ADD_MEMBERSHIP - 客户端地址去重:
Iperf_hostpresent()检查是否已有同 host 连接
功能:
7.6 PerfSocket.cpp — 套接字性能选项
文件: src/PerfSocket.cpp (159 行)
功能: Client 和 Server 共用,在 listen()/connect() 之前设置套接字选项:
void SetSocketOptions( thread_Settings *inSettings ) {
// 1. TCP 窗口大小(SO_RCVBUF / SO_SNDBUF)
setsock_tcp_windowsize(inSettings->mSock, inSettings->mTCPWin, ...);
// 2. TCP 拥塞控制算法(-Z,仅 Linux TCP_CONGESTION)
setsockopt(..., TCP_CONGESTION, ...);
// 3. 多播 TTL(IP_MULTICAST_TTL / IPV6_MULTICAST_HOPS)
setsockopt(..., IP_MULTICAST_TTL, ...);
// 4. IP TOS 字段(-S,Type of Service)
setsockopt(..., IP_TOS, ...);
// 5. TCP MSS(TCP_MAXSEG)
setsock_tcp_mss(inSettings->mSock, inSettings->mMSS);
// 6. TCP No Delay(TCP_NODELAY,禁用 Nagle 算法)
setsockopt(..., TCP_NODELAY, ...);
}
7.7 Launch.cpp — C/C++ 线程桥接
文件: src/Launch.cpp (172 行)
功能: 为 C 线程子系统提供启动 C++ 对象的桥梁函数:
listener_spawn():创建Listener对象,处理守护进程模式,调用Run()server_spawn():创建Server对象并运行client_spawn():创建Client对象 →InitiateServer()→Run()client_init():多线程客户端初始化 — 创建Listener(双向测试),生成-P份 Settings 副本,组织线程启动链
void client_init( thread_Settings *clients ) {
setReport(clients);
Settings_GenerateListenerSettings(clients, &next); // 双向测试
Mutex_Lock(&groupCond);
groupID--;
clients->multihdr = InitMulti(clients, groupID); // 多流聚合头
Mutex_Unlock(&groupCond);
for (int i = 1; i < clients->mThreads; i++) {
Settings_Copy(clients, &next); // 每线程独立副本
unsetReport(next); // 仅第一个报告设置
itr->runNow = next; // 线程链
}
}
7.8 Reporter.c — 报告系统核心
文件: src/Reporter.c (914 行)
InitReport():为传输线程初始化ReportHeader+ ring bufferInitMulti():为多流聚合初始化MultiHeader(包含NUM_MULTI_SLOTS个 slot)ReportPacket():传输线程写入 ring buffer(生产者),需处理 agent 与 reporter 的同步BarrierClient():多流客户端同步 — 所有线程在同一时间起点开始reporter_spawn():Reporter 线程主循环 — 等待ReportCond,处理ReportRoot链表reporter_process_report():递归处理报告链表,按类型分发(SETTINGS → CONNECTION → TRANSFER)reporter_handle_packet():处理单个数据包 — 累加字节,计算抖动(RFC 1889),检测丢包/乱序reporter_condprintstats():条件打印 — 检查时间间隔,计算增量统计reporter_handle_multiple_reports():-P多流聚合 — 按 startTime 匹配 slot,free 计数达到 threads 时打印 SUM 行reporter_print():多格式分发 — 按stats->mode索引函数指针数组
功能:
报告分发表:
report_statistics statistics_reports[kReport_MAXIMUM] = {
reporter_printstats, // kReport_Default
CSV_stats // kReport_CSV
};
RFC 1889 抖动计算:
transit = TimeDifference(packetTime, sentTime);
deltaTransit = transit - lastTransit; // |D(i-1,i)|
stats->jitter += (deltaTransit - stats->jitter) / 16.0; // J = J + (|D| - J)/16
7.9 ReportDefault.c — 默认文本报告
文件: src/ReportDefault.c (304 行)
功能: 生成人类可读的文本报告:
reporter_printstats():打印单流 TCP/UDP 报告(带宽/抖动/丢包/乱序)reporter_multistats():打印[SUM]聚合报告reporter_serverstats():打印服务器端统计reporter_reportsettings():打印客户端/服务器配置摘要reporter_reportpeer():打印连接对端 IP 和端口reporter_reportMSS():MSS/MTU 分析和网络类型推断
网络类型推断逻辑:
if (checkMSS_MTU(inMSS, 1500)) net = "ethernet"; mtu = 1500;
else if (checkMSS_MTU(inMSS, 4352)) net = "FDDI"; mtu = 4352;
else if (checkMSS_MTU(inMSS, 9180)) net = "ATM"; mtu = 9180;
else if (checkMSS_MTU(inMSS, 65280)) net = "HIPPI"; mtu = 65280;
else if (checkMSS_MTU(inMSS, 576)) {net = "minimum"; mtu = 576;}
// checkMSS_MTU = (MTU-40) >= MSS && MSS >= (MTU-80)
8.10 ReportCSV.c — CSV 格式报告
文件: src/ReportCSV.c (158 行)
CSV_stats():打印 CSV 格式的统计行(时间戳, ID, 间隔, 字节, 速度, 抖动, 丢包...)CSV_peer():返回 CSV 格式的对端地址字符串(malloc 分配)CSV_serverstats():组合 peer + statsCSV_timestamp():生成YYYYMMDDHHmmss格式时间戳
功能:
CSV 输出格式:
TCP: timestamp,,,ID,start-end,bytes,bps
UDP: timestamp,,,ID,start-end,bytes,bps,jitter_ms,lost,total,%loss,outoforder
8.11 Locale.c — 本地化字符串
文件: src/Locale.c (336 行)
功能: 集中管理所有用户可见的字符串:
usage_short[]/usage_long1[]/usage_long2[]:帮助文本version[]:版本信息(含线程类型:pthreads/win32 threads/single threaded)separator_line[]:分隔线- 服务器/客户端端口信息
- 报告格式字符串(
report_bw_format,report_bw_jitter_loss_format等) - CSV 格式字符串(多个平台变体:
%lld/%qd/%I64d/%d) - 警告信息(窗口大小、延迟、文件打开失败等)
printf 64位支持的平台变体:
#ifdef HAVE_PRINTF_QD
"%s,%s,%d,%.1f-%.1f,%qd,%qd\n" // BSD 风格
#elif HAVE_QUAD_SUPPORT
"%s,%s,%d,%.1f-%.1f,%lld,%lld\n" // C99 标准
#elif WIN32
"%s,%s,%d,%.1f-%.1f,%I64d,%I64d\n" // MSVC 风格
#else
"%s,%s,%d,%.1f-%.1f,%d,%d\n" // 32 位回退
#endif
8.12 sockets.c — 套接字工具
文件: src/sockets.c (197 行)
setsock_tcp_mss():通过TCP_MAXSEG设置 TCP 最大分段大小,并验证getsock_tcp_mss():查询当前 TCP MSSreadn():Stevens 风格的可靠读取(循环调用read()直到读满 n 字节或 EOF)writen():Stevens 风格的可靠写入(循环调用write()直到写完 n 字节)
功能:
ssize_t readn(int inSock, void *outBuf, size_t inLen) {
size_t nleft = inLen;
while (nleft > 0) {
nread = read(inSock, ptr, nleft);
if (nread < 0) { if (errno == EINTR) continue; else return -1; }
if (nread == 0) break; // EOF
nleft -= nread; ptr += nread;
}
return (inLen - nleft);
}
8.13 SocketAddr.c — 地址操作
文件: src/SocketAddr.c (423 行)
SockAddr_remoteAddr():解析远程地址(-c参数)SockAddr_localAddr():解析本地地址(-B参数)SockAddr_setHostname():DNS 解析(IPv6 用getaddrinfo,IPv4 用gethostbyname+inet_pton回退)SockAddr_getHostAddress():地址转字符串SockAddr_setPort()/SockAddr_getPort():端口设置/获取(主机字节序↔网络字节序)SockAddr_isMulticast():判断是否为多播地址(IPv4: 224.0.0.0/4, IPv6:IN6_IS_ADDR_MULTICAST)SockAddr_are_Equal():完整地址比较(IP + 端口)SockAddr_Hostare_Equal():仅主机地址比较(忽略端口)
功能:
8.14 stdio.c — 数值格式化
文件: src/stdio.c (283 行)
byte_atof()/byte_atoi():解析带宽/大小值(1500, 10M, 1G 等),大写=1024,小写=1000byte_snprintf():将字节数格式化为人类可读字符串(自适应精度:4.2f/4.1f/4.0f)redirect():stdout 重定向到文件(Win32freopen)
功能:
单位转换规则:
大写后缀(2的幂): K=1024, M=1024², G=1024³
小写后缀(10的幂): k=1000, m=1000², g=1000³
8.15 tcp_window_size.c — TCP 窗口管理
文件: src/tcp_window_size.c (178 行)
setsock_tcp_windowsize():设置 TCP 窗口大小(SO_RCVBUF/SO_SNDBUF)- UNICOS 平台:通过
TCP_WINSHIFT支持 > 64KB 窗口 - AIX 平台:通过
TCP_RFC1323启用 RFC 1323 扩展 getsock_tcp_windowsize():查询当前缓冲区大小
功能:
必须在 listen()/connect() 之前调用,否则 > 64KB 的窗口可能无效。
8.16 Extractor.c — 文件数据输入
文件: src/Extractor.c (189 行)
Extractor_Initialize():打开文件(-F选项),设置块大小Extractor_getNextDataBlock():读取下一个数据块Extractor_canRead():检查文件是否可读(非 NULL + 非 EOF)Extractor_reduceReadSize():UDP 模式下减少读取尺寸以容纳时间戳头- 用于测量不同数据类型(压缩/多媒体/原始)的传输速率
功能:
8.17 List.cpp — 客户端地址链表
文件: src/List.cpp (135 行)
功能: UDP 服务器用于跟踪已连接客户端地址的链表:
Iperf_pushback():添加节点到链表头Iperf_delete():删除匹配地址的节点Iperf_present():精确地址查找(IP + 端口)Iperf_hostpresent():主机级查找(仅 IP,忽略端口)Iperf_destroy():销毁整个链表
全局变量: clients(链表头)、clients_mutex(保护锁)
8.18 gnu_getopt.c — 命令行解析
文件: src/gnu_getopt.c (819 行)
功能: GNU C Library 的 getopt_long 实现,从 glibc 中提取并重命名(加 gnu_ 前缀),避免与系统 getopt 冲突。
- 支持三种参数排列模式:
REQUIRE_ORDER(POSIX)、PERMUTE(默认 GNU 风格)、RETURN_IN_ORDER - 环境变量
POSIXLY_CORRECT可切换到严格 POSIX 模式 - 长选项支持:
--option=value和缩写匹配
8.19 service.c — Windows 服务集成
文件: src/service.c (602 行)
功能: 仅 Win32 平台,将 iperf 注册为 Windows 服务(SCM)。
service_main():服务入口点,注册控制处理器,调用ServiceStart()service_ctrl():服务控制处理器(STOP / INTERROGATE)CmdInstallService():使用CreateService()安装服务并启动CmdRemoveService():停止并删除服务ServiceStart():初始化 Settings → 解析命令行 → 启动客户端/监听器ServiceStop():调用Sig_Interupt(1)或sig_exit(1)ReportStatusToSCMgr():向 SCM 报告服务状态
8.20 compat/Thread.c — 线程子系统
文件: compat/Thread.c (418 行)
thread_init():初始化线程子系统(Solaris 上用pthread_setconcurrency(3))thread_start():启动线程(POSIXpthread_create/ Win32CreateThread/ 单线程直接调用)thread_stop():停止线程(POSIXpthread_cancel+pthread_exit/ Win32TerminateThread)thread_run_wrapper():线程入口函数 — 根据mThreadMode分发到listener_spawn/server_spawn/client_spawn/reporter_spawnthread_joinall():等待线程计数归零thread_setignore()/thread_unsetignore():Reporter 线程用,允许在无待处理报告时让主线程退出thread_register_nonterm()/thread_unregister_nonterm():Listener 线程用,Ctrl-C 时忽略thread_release_nonterm():Ctrl-C 时释放所有非终止线程
功能:
8.21 compat/signal.c — 跨平台信号处理
文件: compat/signal.c (181 行)
功能:
- 使用
sigaction()安装信号处理器(SA_INTERRUPTfor SIGALRM,SA_RESTARTfor others) sig_exit():安全退出,防止多次调用
Unix 路径:
- 使用
SetConsoleCtrlHandler()的sig_dispatcher分发CTRL_C_EVENT→SIGINT、CTRL_CLOSE/LOGOFF/SHUTDOWN_EVENT→SIGTERM handlers[_NSIG]数组存储函数指针,模拟 Unix 信号处理
Win32 路径:
8.22 compat/delay.cpp — 微秒延迟
文件: compat/delay.cpp (77 行)
功能: 使用 POSIX nanosleep() 实现高精度微秒延迟,支持 EINTR 中断后续传。
void delay_loop(unsigned long usec) {
struct timespec requested, remaining;
requested.tv_sec = 0;
requested.tv_nsec = usec * 1000L;
while (nanosleep(&requested, &remaining) == -1)
if (errno == EINTR)
requested = remaining;
else break;
}
8.23 include/Settings.hpp — 核心数据结构
文件: include/Settings.hpp (426 行)
- 指针:
mFileName,mHost,mLocalhost,mOutputFileName,Extractor_file,reporthdr,multihdr,runNow,runNext - 整数:
mThreads(-P),mTOS(-S),mSock(fd),Extractor_size,mBufLen(-l),mMSS(-M),mTCPWin(-w),flags(28个布尔位) - 枚举:
mThreadMode(Server/Client/Reporter/Listener),mReportMode(Default/CSV),mMode(Normal/DualTest/TradeOff) - 64位:
mUDPRate(-b),mAmount(-n/-t) - 浮点:
mInterval(-i) - 端口:
mListenPort(-L),mPort(-p) - 地址:
peer(对端),local(本地), 含长度 - 线程:
mTID,mHandle(Win32)
thread_Settings 结构体是所有运行状态的容器,包含:
9. 网络测试工作流(实战)
以下内容整合自 3 份参考文档的实际测试经验。
9.1 双网卡同时测试
场景: 服务器有两张网卡,需要同时测试双向带宽。
环境准备:
# 1. 关闭防火墙(测试期间)
systemctl stop firewalld
# 2. 配置网卡 IP(临时)
ifconfig enp100s0f0 192.168.1.10 netmask 255.255.255.0 up
ifconfig enp100s0f1 192.168.2.10 netmask 255.255.255.0 up
# 或者永久配置(Debian/Ubuntu)
# 编辑 /etc/network/interfaces
auto ens1f0np0
iface ens1f0np0 inet static
address 192.168.1.10
netmask 255.255.255.0
auto ens1f1np1
iface ens1f1np1 inet static
address 192.168.2.10
netmask 255.255.255.0
测试步骤:
# 服务器端 — 两台机器各启一个 iperf 服务
iperf -s -p 5001 &
iperf -s -p 5002 &
# 客户端 — 同时启动两个测试
iperf -c 192.168.1.10 -p 5001 -P 10 -t 3600 -i 3 &
iperf -c 192.168.2.10 -p 5002 -P 10 -t 3600 -i 3 &
9.2 长时间压力测试(6 轮)
参考 Storage HDDS-CONF Function Validation Guide 的 6 轮压力测试模式:
# 服务器端
iperf -s
# 客户端 — 执行 6 轮
for round in 1 2 3 4 5 6; do
echo "=== Round $round ==="
iperf -c <server_ip> -P 10 -t 3600 -i 5 | tee iperf_round${round}.log
sleep 60
done
9.3 环境测试参数对照表
| 参数 | 网卡测试文档 | 系统操作文档 | 存储验证文档 |
|---|---|---|---|
| 并行流 (-P) | 10 | 10 | 10 |
| 持续时间 (-t) | 1000s | 3600s (1h) | 3600s (1h) |
| 报告间隔 (-i) | 3s | 3s | 5s |
| 网卡命名 | enp100s0f0/1 | eth*/eth# | ens1f0np0/1 |
| IP 方式 | ifconfig (临时) | ifconfig (临时) | /etc/network/interfaces (永久) |
| 防火墙 | systemctl stop | systemctl stop firewalld | 未明确提及 |
| 额外测试 | 无 | fio, burning, ipmitool | LogFilter 集成 |
9.4 多端口并发测试
# 同时测试两个端口
# 终端1
iperf -c <server_ip> -p 5001 -t 3600 -i 5 > port_5001.log 2>&1 &
# 终端2
iperf -c <server_ip> -p 5002 -t 3600 -i 5 > port_5002.log 2>&1 &
wait
9.5 与 LogFilter 集成
在 SIT 验证场景中,iperf 测试日志可被 LogFilter 工具收集分析:
1. 将 iperf 输出重定向到日志文件
2. LogFilter 配置
reports/ 目录包含 dmesg.log, messages.log, mcelog.log 等
3. iperf 结果可与系统日志对照分析
10. 使用示例
9.1 TCP 基本带宽测试
# 服务器
iperf -s
# 客户端 — 30秒测试,每2秒报告
iperf -c 192.168.1.100 -t 30 -i 2
9.2 UDP 带宽测试(指定速率)
# 服务器
iperf -s -u
# 客户端 — 100 Mbits/s UDP
iperf -c 192.168.1.100 -u -b 100M -t 30
9.3 多流并行测试
# 10 个并行流,更充分利用带宽
iperf -c 192.168.1.100 -P 10 -t 60
9.4 大窗口 TCP 测试
# 设置 256KB TCP 窗口,打印 MSS
iperf -c 192.168.1.100 -w 256K -m
9.5 双向测试
# 同时双向(客户端和服务器同时发送数据)
iperf -c 192.168.1.100 -d
# 交替双向(客户端先发完,服务器再发)
iperf -c 192.168.1.100 -r
9.6 IPv6 测试
# 服务器
iperf -s -V
# 客户端
iperf -c fe80::1%eth0 -V
9.7 多播测试
# 服务器加入多播组
iperf -s -u -B 224.0.55.55
# 客户端向多播组发送
iperf -c 224.0.55.55 -u -T 5 -t 30
9.8 CSV 输出
# 输出 CSV 格式结果
iperf -c 192.168.1.100 -y C -t 30
9.9 Windows 服务模式
# 安装服务
iperf -s -D
# 移除服务
iperf -s -R
10.10 从文件发送数据
# 使用指定文件作为数据源(测试压缩/多媒体数据传输速率)
iperf -c 192.168.1.100 -F /path/to/datafile
10.11 绑定特定接口
# 服务器绑定到特定 IP
iperf -s -B 10.0.0.1
# 客户端指定源地址
iperf -c 192.168.1.100 -B 10.0.0.2
10.12 按数据量测试(替代按时长)
# 传输 1GB 数据后停止
iperf -c 192.168.1.100 -n 1G
10.13 服务器守护进程模式
# 后台运行 iperf 服务器
iperf -s -D
10.14 组合参数实战
# 完整 UDP 测试:100Mbps, 10 流, 1 小时, CSV 输出, 排除连接报告
iperf -c 192.168.1.100 -u -b 100M -P 10 -t 3600 -i 5 -y C -x C
11. 版本历史
| 版本 | 日期 | 变更 |
|---|---|---|
| 2.0.5 | 2010-07-14 | 当前版本 |
| 2.0.4 | 2008-04-08 | 修复多播和兼容性问题 |
| 2.0.3 | 2007-03-13 | 修复 IPv6 和流量控制问题 |
| 2.0.2 | 2005-07-01 | 修复 TCP 窗口和信号处理 |
| 2.0.1 | 2005-05-01 | 首个 2.0 稳定版 |
- Mark Gates — 原作者
- Alex Warshavsky — 原作者
- Kevin Gibbs — Reporter 系统、多流支持
- Ajay Tirumala — SocketAddr、Extractor、Locale
- Jon Dugan — 维护、手册页
- Feng Qin — Windows 服务集成
- Andrew Gallatin, Stephen Hemminger — 网络优化
核心贡献者:
线程模型: pthreads(首选)、win32 threads、single threaded(回退)
**参考文档**: 网卡测试-iperf.pptx (2018, Joyce Lv) · linux系统操作疑问.docx · Storage HDDS-CONF Function Validation Guide.pdf
>
**本手册覆盖**: iperf-2.0.5 全部 159 个文件,包括 src/ (20 个源文件)、include/ (28 个头文件)、compat/ (9 个兼容层文件)、doc/ (3 个文档文件)、man/ (1 个手册页)、m4/ (3 个 autoconf 宏)、configure.ac 和 autogen.sh 构建脚本。