☰
RK平台Android14的iperf3 unable to create stream报错修复
2026/9/28 16:54:23 网站建设 项目流程

先说结论,报错本身并不复杂,复杂的是RK平台Android14这套环境把iperf3的所有小毛病都放大了。无论是RK3568、RK3576还是更早的RK3399,在做熟悉度测试、车载网络测试、量产吞吐验证时,大家几乎都会踩一遍“unable to create stream”。这篇文章不灌水,直接把报错原理、定位过程和最终能落地的修复方案一次性讲清楚。

这里适合两类人看:一类是刚接手RK平台、第一次在Android14上跑iperf3,遇到这个报错不知道从哪查起;另一类是已经被这个报错折磨了一阵子,试过换端口、重跑进程都没用的人。我尽量把每一步“为什么这么做”也写出来,这样换一套板子、换一个平台,你也能自己延展开。

1. 问题现场与报错定位

1.1 事故现场:RK平台Android14上iperf3拒绝工作

先说当时的环境:一台RK3576的开发板,系统是Android14,想要验证板子Ethernet口的吞吐能力。PC端是Ubuntu 22.04,装的是iperf3 3.9,Android端手动push了一个aarch64的iperf3静态二进制到/data/local/tmp/。PC端先启动iperf3 -s监听5201端口,Android端执行:

adb shell cd /data/local/tmp chmod +x iperf3 ./iperf3 -c 192.168.1.100 -t 10

结果没有像预期那样刷出带宽数据,而是立刻弹出一句:

iperf3: error - unable to connect to server: unable to create stream: Connection refused

如果你看到的报错只有“unable to create stream”,没有后面的具体原因,那多半是Android shell的输出被截断了,或者iperf3是精简版本。这个细节很重要,因为“unable to create stream”只是一个总入口,真正的原因在冒号后面的最后一段话里。

我第一次看到这个报错时,第一反应是server没启动,回去检查,server确实在跑。于是怀疑端口被占,换了个5202端口,还是同样报错。又怀疑是iptables防火墙拦截,但RK平台默认不会有那么严格的出站限制。最后来回折腾了一个多小时,才意识到问题出在iprocess残留和参数配合上。事实证明,这个报错背后的坑一共就几类,多数情况下都不是那种特别神秘的原因。

1.2 “unable to create stream”到底在说什么

要搞清楚这个报错,得先知道iperf3的“stream”创建过程。

iperf3的模型不是老式iperf2那样一个进程瞬间建立一堆连接。iperf3在创建连接前,会先根据参数-P指定的并发流数量(默认是1),逐个创建socket。每一个socket创建、bind、connect的完整过程,在iperf3内部都叫“creating stream”。只要其中任何一步失败,iperf3就会统一返回“unable to create stream”,后面再跟具体errno对应的文本描述。

所以“unable to create stream”本身没有诊断价值,有价值的是它的下半句:

  • Connection refused:目标端口没有进程监听,或者防火墙把报文丢弃了。
  • Permission denied:Socket创建/连接受限,通常是权限或SELinux在拦截。
  • Cannot assign requested address:本机网卡没配好IP地址,或者接口没有up。
  • Address already in use:本地端口被占用,通常是上一次iperf3还没退出。

搞清楚这一点后,后面的排查就变成了一道填空题:先看报错的下半句是什么,再针对性地检查对应环节。

1.3 排查前的工具箱准备

在RK平台上排查这种问题,和标准Linux服务器稍有区别,因为Android有几个特殊的限制条件需要提前摸清。

首先是确认iperf3二进制的来历。很多人会随手找一个“能在手机上跑的iperf3”APK或二进制push进去,如果架构不匹配或者依赖库缺失,报错可能根本不是“unable to create stream”,而是“No such file or directory”或“Exec format error”。如果进制本身是好的,再往下排查。

其次,先确认板子的root权限可用。Android14的adb root在部分定制固件上不一定生效,需要在开发者选项里打开“Root authorization”,或者用adb shell setenforce 0测试SELinux是否允许切换。这一条会直接影响后面的修复路径。

最后,建议准备一个能直接进板子shell的终端,不要只依赖adb one-shot命令。因为排查时要同时开server和client、看后台进程、观察/proc文件,来回切换adb shell会更麻烦。我在实际测试时通常开两个终端,一个固定在PC端,一个固定在板子端。

2. 根因逐个击破:四类最常见的触发条件

2.1 服务端没起来,或者“假死”占着端口

这是最基础也最容易被忽视的一类。“unable to create stream: Connection refused”最常见的原因就是服务端压根没在监听。有些同事在板子上跑iperf3 server后,按Ctrl+C退出,但进程因为僵尸状态没有完全释放端口。此时你再在板子上开新的server,会提示端口被占用,而PC端去连接时反而收到Connection refused。

排查方法分两步:

第一步,看进程。在服务端执行:

ps -A | grep iperf

如果看到多个iperf3进程残留,先杀掉:

killall iperf3

如果没有killall命令,可以用循环:

for pid in $(ps -A | grep iperf3 | awk '{print $2}'); do kill -9 $pid; done

第二步,看端口监听状态。执行:

netstat -anp | grep 5201

或者用ss(Android上不一定有)。正常时应该看到类似:

LISTEN 0 128 0.0.0.0:5201 0.0.0.0:*

如果端口被占用但LISTEN的不是iperf3,那就是别的进程占用了,要么换端口,要么处理掉占用进程。

2.2 Android权限与SELinux策略才是重灾区

在RK平台Android14上跑网络测试,SELinux绝对是绕不开的一关。大部分开发板的userdebug固件默认SELinux可能是Enforcing,而iperf3这种需要创建原始socket、绑定任意端口、监听UDP/TCP的工具,很容易被SELinux策略拦住。

报错形式通常不是“Permission denied”这么直白。我遇到过很多次,SELinux拦截后iperf3客户端在创建socket阶段就直接失败,报成“Cannot assign requested address”或“Operation not permitted”,一开始容易被误导去查IP配置。

快速判断SELinux是否在捣乱,用一条命令:

getenforce

如果输出是Enforcing,临时放行:

setenforce 0

然后重新执行iperf3测试。如果问题消失,就确认是SELinux策略问题。

需要注意的是,setenforce 0重启后会失效。如果你只是做一次短时吞吐测试,这个办法完全没问题;如果是要放在产线自动化或长期测试环境中,就得把定制固件里的SELinux策略补丁打上,允许shell域使用网络相关的能力。这一步对普通测试人员来说不太现实,但如果你们和固件团队能协同,这是最干净的方案。

2.3 动态库缺失与二进制不匹配:RK平台的经典坑

还有一个高发问题,是push上去的iperf3跑不起来,或者跑起来后功能异常。

很多从网上下载的iperf3二进制是面向“通用Linux”编译的,依赖libc.so.6、libstdc++.so.6等标准库路径。Android虽然也是Linux内核,但glibc换成了bionic,很多库路径都不一样。你随便找一个PC版iperf3 push到/data/local/tmp/下,执行时大概率报“No such file or directory”或者“not found”,别怀疑语法问题,这就是找不到动态库的表现。

所以我在RK平台上从来不用动态链接的iperf3,一律用NDK交叉编译的静态版本。有关编译步骤后面会详细说,这里先强调一个排查技巧:

file ./iperf3

如果输出包含“statically linked”,那是好情况。如果显示依赖动态库,看它依赖了哪些:

readelf -d ./iperf3

只要出现libc.so.6这类glibc库名,基本可以放弃动态版本,直接改用静态编译产物。

2.4 并发流参数与文件描述符限制

“unable to create stream”还有一种隐蔽的原因:参数-P设得过大,导致瞬间创建的socket数量超过系统文件描述符限制。

Linux/Android默认每个进程的文件描述符上限通常是1024(ulimit -n),但Android的进程限制会受/system/下init.rc配置影响,有些定制固件会卡在256或更小。当你在iperf3命令里写-P 64,客户端要同时创建64个socket,如果fd上限不够,创建第几十个socket时就会失败。

遇到这个问题时,报错可能非常迷惑:unable to create stream: Too many open files in system,或者干脆在连接过程中随机失败。

排查方法:

ulimit -n cat /proc/sys/fs/file-max

如果ulimit -n很小,可以在root shell里调大:

ulimit -n 65535

但这只对当前shell有效,重新打开adb shell后失效。更稳定的做法是测试命令本身降低-P,或者先跑单流确认稳定,再逐步增加并发流数。

3. 终极修复方案:从临时绕过到一劳永逸

3.1 方案A:清理残留进程,换端口跑

最省事的第一板斧,适合只做一次快速测试的情况。

在PC端和Android端都执行一遍:

killall iperf3

然后换一个端口,比如5202,服务端和客户端都改成一致:

# PC端 iperf3 -s -p 5202 # Android端 ./iperf3 -c 192.168.1.100 -p 5202 -t 30

这个方案能解决大部分“Connection refused”问题,因为它同时处理了残留进程和端口占用。换端口的另一个好处是避开某些设备上默认端口被安全扫描或系统自动化脚本占用的场景。

但这里有个容易被忽略的点:两端端口必须完全一致,而且如果中间有路由/NAT设备,还要确保防火墙没有阻断高端口通信。

3.2 方案B:用UDP打流参数绕开连接队列

如果是TCP模式下报“unable to create stream”,但你又怀疑服务端本身没问题,可以改用UDP模式做一次快速验证。UDP打流命令是:

./iperf3 -c 192.168.1.100 -u -b 500M -t 30

-u表示UDP,-b表示目标带宽。UDP模式下iperf3不用处理TCP三次握手和连接队列,很多TCP场景下无法创建连接的问题,在UDP模式下可能直接就能跑起来。这和“用ping先验证链路”的思路类似,都是先把最难缠的连接层绕过,确认底层的IP网络是通的。

UDP模式还有一个好处:它能直观反映链路丢包率、抖动和带宽上限,尤其适合做车载以太网、USB RNDIS、WiFi空口这类测试。测试时服务端也要加-u参数:

iperf3 -s -u

服务端不加-u也没关系,iperf3会自动处理,但加上更规范。如果UDP模式能出数据,TCP模式却报错,问题大概率集中在TCP状态或SELinux/权限层面,可以继续顺着2.2节的思路查。

3.3 方案C:NDK交叉编译静态iperf3

如果说“终极修复方案”里只能留一个,那就是这个:用NDK交叉编译一个完全静态的iperf3。它能同时解决架构不匹配、动态库缺失、SELinux部分限制、权限不足等好几个问题。

先准备NDK环境,以r25c为例:

export NDK=/opt/android-ndk-r25c export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64 export TARGET=aarch64-linux-android export API=28 export CC=$TOOLCHAIN/bin/${TARGET}${API}-clang export CXX=$TOOLCHAIN/bin/${TARGET}${API}-clang++

下载iperf3源码后,进入源码目录:

./configure --host=${TARGET} --prefix=/data/local/tmp/iperf3 \ --disable-shared --enable-static \ CFLAGS="-static-libgcc -static-libstdc++ -O2" \ LDFLAGS="-static"

然后编译:

make -j$(nproc)

编译完成后,在源码目录里的src/iperf3就是我们要的产物。push到板子并赋予执行权限:

adb push src/iperf3 /data/local/tmp/ adb shell chmod 755 /data/local/tmp/iperf3

这里重点解释一下为什么强制--disable-shared和-static。Android的bionic库和普通Linux glibc差异很大,动态链接的iperf3在板子上只要有一点依赖路径对不上,你就会见到“No such file or directory”这种让人怀疑人生的报错。静态编译后,所有库都打进二进制里,对板子环境几乎没有依赖。这也是我在多个RK平台板子上反复验证后最稳妥的姿势。

3.4 方案D:关SELinux/提升fd,给测试环境“松绑”

如果静态iperf3已经跑起来了,但连接时还是被SELinux拦,可以临时放开整个系统的SELinux限制。注意,这只建议在开发调测阶段用,产线长期运行还是走固件策略补丁。

在root shell下执行:

setenforce 0

同时把文件描述符上限调高:

ulimit -n 65535

然后再跑测试。如果还不行,检查/dev/socket、/proc/sys/net/ipv4/ip_forward这些节点是否被限制。某些定制固件把网络命名空间和netd控制得很死,需要额外把测试进程放到shell域或增加SELinux allow规则。

3.5 方案E:PC端Server部署与版本匹配

测试链路里还经常有一半问题出在PC端。比如PC端装了iperf3 3.1,Android端装了iperf3 3.9,版本跨度过大时部分参数兼容性会出问题;再比如PC端服务端本身有防火墙,Windows Defender或Ubuntu ufw默认放行不全。

服务端部署建议:

  • Ubuntu/Debian:apt install iperf3
  • Windows:用官方编译好的exe
  • macOS:brew install iperf3

跑服务端时,确保监听在所有网卡或指定测试网卡:

iperf3 -s -i 1

如果PC端有多个网卡,用-B指定服务端绑定的IP:

iperf3 -s -B 192.168.1.100

版本匹配上,我建议两端都使用3.9以上版本,因为3.x系列在连接参数和输出格式上的兼容性相对更好。另外,每次跑测试前先对照版本号,确认两端大版本一致。

4. 实测验证与配套经验

4.1 一次完整的上手流程

到了实操环节,我按自己的习惯给出一次标准流程,你可以直接照着走一遍。

准备阶段:

  1. 确认板子端ping通PC端IP。
  2. 确认iperf3二进制是静态编译且架构正确。
  3. 确认两端iperf3大版本一致。

启动服务端:

# PC端 iperf3 -s -i 1

启动客户端:

# Android端 /data/local/tmp/iperf3 -c 192.168.1.100 -t 60 -i 1 -P 4

如果客户端输出正常,你会看到类似这样的行:

[ ID] Interval Transfer Bitrate Retr [ 4] 0.00-1.00 sec 113 MBytes 950 Mbits/sec 1

如果依旧报“unable to create stream”,严格按照这个顺序排查:

  • 看报错下半句是Connection refused还是Permission denied。
  • Connection refused:先杀残留进程,换端口,再试。
  • Permission denied:关SELinux,再试。
  • 还不行:用UDP模式-u -b 100M,确认链路通不通。
  • UDP通、TCP不通:查TCP连接参数、fd限制、中间防火墙。

这套流程我实际用了很多次,基本上能在5分钟内把问题定位到具体层面。

4.2 性能和稳定性测试中容易忽视的“隐形坑”

“unable to create stream”修好之后,不代表测出来的数据就准确。RK平台跑网络带宽测试还有几个很容易影响结果、但和报错没有任何关系的坑。

CPU频率和DDR频率。RK平台默认的省电策略会把CPU频率压得很低,DDR频率也会自动动态调频。同样是千兆以太网,CPU锁在低频率时带宽可能只有600Mbps,一旦跑满负载又会掉帧。测试前建议锁频,Android端通常用/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor设置为performance,DDR频率同理。

屏幕常亮和音频道。测试时板子如果跟着熄屏,部分系统会进入低功耗模式,网卡也可能进入节能状态。执行:

svc power stayon true

另外有一些RK板子存在HDMI/音频路由的关联问题,比如RK3576插上HDMI后媒体声音消失,这虽然不是网络测试直接相关,但在做多媒体+网络并发测试时很容易干扰判断,建议测试时单独立项排查。

TCP窗口和拥塞控制。Android内核默认的TCP参数通常偏向省电而非高性能,跑长距离开宽带时,可能需要调整/proc/sys/net/ipv4/tcp_window_scaling、tcp_rmem等参数。

4.3 常见报错速查表

这里整理一份我实测下来比较常用的速查表,遇到问题先对照一下:

报错信息可能原因解决方法
unable to create stream: Connection refused服务端未启动/端口不对/残留进程换端口,killall iperf3,重启服务端
unable to create stream: Permission deniedSELinux拦截/socket权限不足setenforce 0,或打SELinux policy补丁
unable to create stream: Cannot assign requested address本机网卡无IP/接口未up检查ip addr,配置网卡地址
unable to create stream: Address already in use本地端口被占用换端口,或杀掉占用进程
unable to create stream: Too many open filesfd限制/参数-P过大ulimit -n 65535,降低-P值
No such file or directoryiperf3动态库依赖缺失/架构不对改用NDK静态编译版本
Exec format errorCPU架构不匹配换成aarch64版本

5. 写在最后的工程建议

整篇写下来,你会发现“unable to create stream”本身并不可怕,真正麻烦的是它把iperf3、Android、RK平台三方的问题全揉在了一起。我的建议是,任何团队做RK平台网络测试时,第一件事就是把静态编译的iperf3纳入版本管理,不要在网盘里随便找一个二进制用。二进制一旦确定能跑,后面遇到的多数报错都能收敛到权限、端口、参数这三件事上。

如果条件允许,最好把整个测试环境固化下来,包括PC端的系统镜像、服务端iperf3包版本、Android端的iperf3二进制、测试脚本、锁频方式。不要每次测试都临时打量环境,那样很容易陷入“报错—查半天—发现是环境变了”的循环。

从我个人的经验看,RK平台Android14的适配虽然比早期版本复杂,但只要把SELinux、动态库、端口、fd这四个点提前控制好,iperf3在板子上跑起来非常顺。希望这篇文章能帮你省下当初我折腾的那几个小时。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询