全面的 iPerf3 Android平台移植編譯、運行過程記錄


https://blog.csdn.net/China_Style/article/details/109660170

 

1. iPerf 簡介

iPerf 是什么?無需我多言,官網這條醒目的宣傳語,已表達的很簡潔、准確,甚至透露着一絲霸氣:

iPerf——支持TCP、UDP和SCTP的終極測速工具!


iPerf 官方支持的平台非常全面,包括:Windows、Android、iOS、macOS 和 Linux 的多個發行版本。但遺憾的是,Android 版本提供的是兩個開發好的、包含 iPerf 工具的Android應用,可以在谷歌應用商店下載。不像其他平台,提供了單獨的 iPerf 可執行程序。

我結合自己的需求,獲取源碼,用 NDK 交叉編譯一個可以在 Android 平台運行的 iPerf 工具。期間確實也遇到了不少的問題,Google 了無數次,也參考了很多其他博客,我將用這篇博客整理記錄整個實踐過程,方便自己查看,也希望幫助后續探索的朋友避一些坑。

作為學習記錄,我這里記錄了3種編譯方式:傳統交叉編譯,以及更符合 Android 平台的 ndk-build 和 CMake 編譯。實際應用中選擇一種合適方式就好。

iPerf 有 iPerf2 和 iPerf3 兩個版本,兩者區別可以參考官網或其他資料,本博客記錄的是移植運行 iPerf3 v3.1.3 的過程。源碼下載地址:https://iperf.fr/iperf-download.php#source

2. 移植環境

  • 移植時間:2020年11月
  • iPerf3:iperf-3.1.3-source.tar.gz
  • 開發編譯平台:macOS 10.14.6
  • NDK 版本:ndk-r17c (17.2.4988734),通過 Android Studio 內的 SDK Manager 安裝。

3. 傳統交叉編譯

編譯階段主要包括下面4個步驟:

  1. 下載源碼壓縮包,解壓后進入源碼根目錄。
  2. 配置交叉編譯工具鏈;
  3. ./configure --prefix=absolutepath/to/install_dir
  4. make && make install

3.1 本機平台編譯測試

在 macOS 或 Linux 平台下,如果執行上面那樣寫的第1、3、4步,不配置任何額外的參數,編譯完成后,在 --prefix 指定的路徑 bin 目錄下,就已經生成了可以在本機上直接運行的可執行程序,非常簡單,有興趣的讀者可以試試。

3.1.1 macOS 可能遇到的問題

  1. make 過程報錯:clang: error: the clang compiler does not support -pg option on versions of OS X 10.9 and later。

解決方法:查看一下 iperf-3.1.3/src 里面的 Makefile 和 Makefile.am 我們可以發現,編譯器的 -pg 選項主要是編譯 iperf_profile 用到的。至於 iperf_profile 是個啥,給個參考:iPerf Issues #335: What's difference between iperf3_profile and iperf3?。按里面的回答就是,這個東西連很多 iPerf 項目的成員自己都沒用過,通常我們也用不上,那我們就可以去掉這個選項。具體操作方式有兩種:

  • 方式一:直接修改 iperf-3.1.3/src/Makefile,找到 iperf3_profile_CFLAGS 和 iperf3_profile_LDFLAGS 賦值的地方(第613行左右),去掉 -pg 參數,然后直接重新執行 make 命令。
  1. # To fix: "clang: error: the clang compiler does not support -pg option on versions of OS X 10.9 and later" compile error on macOS.
  2. #iperf3_profile_CFLAGS = -pg -g
  3. iperf3_profile_CFLAGS = -g
  4. iperf3_profile_LDADD = libiperf.la
  5. # To fix: "clang: error: the clang compiler does not support -pg option on versions of OS X 10.9 and later" compile error on macOS.
  6. #iperf3_profile_LDFLAGS = -pg -g
  7. iperf3_profile_LDFLAGS = -g
  • 方式二:修改 iperf-3.1.3/src/Makefile.in 文件,找到 iperf3_profile_CFLAGS 和 iperf3_profile_LDFLAGS 賦值的地方(第613行左右),去掉 -pg參數,然后執行 ./configure 重新生成 的Makefile,再 make。

3.2 配置交叉編譯工具鏈

根據 NDK 指南,使用 NDK 編譯代碼有三種方式:ndk-build、CMake、獨立工具鏈。獨立工具鏈方式雖然被標記為已廢棄,但非常適合用於編譯包含 configure 腳本的開源項目,iPerf3 就非常符合這種情況,所以我這里選擇用獨立工具鏈的方式。這一步可以參考 NDK 指南獨立工具鏈的創建工具鏈章節。為了使用方便,我指定了在 iPerf 源碼根目錄的 ndk-standalone 目錄中存放獨立工具鏈,這個名字和路徑可以根據自己需要更改。

  1. cd iperf-3.1.3
  2. $NDK/build/tools/make_standalone_toolchain.py \
  3. --arch arm \
  4. --api 21 \
  5. --install-dir /Users/shenyong/iperf-3.1.3/ndk-standalone \
  6. --force

然后我們在終端中,把獨立工具鏈的下的 bin 目錄臨時添加到 PATH 環境變量中。

export PATH=/Users/shenyong/iperf-3.1.3/ndk-standalone/bin:$PATH

此時當我們在終端輸入 arm,再按 Tab 鍵進行命令補全時,命令會自動補全為:arm-linux-androideabi-,再次雙擊 Tab,就會看到很多以 arm-linux-androideabi- 為前綴的交叉編譯工具命令。可以用 which 驗證,這些命令正是位於我們創建的獨立工具鏈目錄中:

  1. $ arm-linux-androideabi-
  2. arm-linux-androideabi-addr2line arm-linux-androideabi-clang++ arm-linux-androideabi-gcc-4.9 arm-linux-androideabi-gcov-tool arm-linux-androideabi-objcopy arm-linux-androideabi-strip
  3. arm-linux-androideabi-ar arm-linux-androideabi-cpp arm-linux-androideabi-gcc-4.9.x arm-linux-androideabi-gprof arm-linux-androideabi-objdump
  4. arm-linux-androideabi-as arm-linux-androideabi-dwp arm-linux-androideabi-gcc-ar arm-linux-androideabi-ld arm-linux-androideabi-ranlib
  5. arm-linux-androideabi-c++ arm-linux-androideabi-elfedit arm-linux-androideabi-gcc-nm arm-linux-androideabi-ld.bfd arm-linux-androideabi-readelf
  6. arm-linux-androideabi-c++filt arm-linux-androideabi-g++ arm-linux-androideabi-gcc-ranlib arm-linux-androideabi-ld.gold arm-linux-androideabi-size
  7. arm-linux-androideabi-clang arm-linux-androideabi-gcc arm-linux-androideabi-gcov arm-linux-androideabi-nm arm-linux-androideabi-strings
  8. $ which arm-linux-androideabi-gcc
  9. /Users/shenyong/iperf-3.1.3/ndk-standalone/bin/arm-linux-androideabi-gcc

一定注意:這是一種臨時添加方法,只在當前執行命令的終端窗口有效,在其他已有終端和新打開的終端是不生效的!做這一步是為了方便后面配置和編譯執行,可以精簡一些參數項;同時不用添加到 .bashrc 中使其一直生效以至於影響電腦上的其他開發配置。是否需要配置為使其始終生效,可根據個人情況自行評估。

3.3 執行 ./configure

一開始其實我也不知道要怎么配置參數,所以參考了這篇 Medium 博客:How to compile iperf3 for Android(需要梯子),原文作者的參數項如下:

  1. ./configure \
  2. --host=arm-linux-androideabi \
  3. --prefix=/Users/shenyong/iperf-3.1.3/out_install \
  4. -C \
  5. CC=arm-linux-androideabi-gcc \
  6. CFLAGS=-static \
  7. CXX=arm-linux-androideabi-g++ \
  8. CXXFLAGS=-static \
  9. AR=arm-linux-androideabi-ar \
  10. RANLIB=arm-linux-androideabi-ranlib

參數解釋:

  • --host:交叉編譯時的目標平台工具鏈前綴;
  • --prefix:編譯完成后,make install 的安裝目錄,如未指定,默認是 /usr/local。這個路徑必須是絕對路徑,否則configure腳本執行會報錯提示。
  • -C:表示 configure 會啟用緩存,保存在 config.cache 文件中。可以用 ./configure -h 查看幫助信息
  • CXX、CXXFLAGS、CC、CFLAGS、AR、RANLIB:這幾個是交叉編譯需要配置的變量,用於指定編譯器等。在獨立工具鏈 bin 目錄中包含 gcc 和 clang 兩種編譯器,可以按需選擇。由於從 ndk-r13開始,NDK 默認使用 clang 編譯,所以如果我們想要用 gcc 編譯,就必須手動指定 CC、CXX、AR、RANLIB 等工具,在以后的 NDK 更新版本中,gcc 工具鏈可能會被移除。

因為我前面在 PATH 環境變量中添加了工具鏈編譯器的路徑,所以可以不用像參考博客那樣寫很長一串 gcc、g++ 等的絕對路徑,這樣看起來更簡潔清晰一些。經過我的測試,原博客的這個配置方案,雖然執行 ./configure 不會有問題,但是在 make 階段會遇到下面記錄的其他問題,當時我在這一塊也爬了好久的坑~

我使用的一種經測試能順利完成編譯的配置如下:

  1. ./configure \
  2. --host=arm-linux-androideabi \
  3. --prefix=/Users/shenyong/iperf-3.1.3/out_install \
  4. CC=arm-linux-androideabi-gcc \
  5. CFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s" \
  6. CXX=arm-linux-androideabi-g++ \
  7. CXXFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s" \
  8. AR=arm-linux-androideabi-ar \
  9. RANLIB=arm-linux-androideabi-ranlib

參數解釋:

  • -D__ANDROID_API__=14 -pie -fPIE:這幾個都是為了解決對應的編譯問題添加的,后面說到對應問題時有解釋;
  • -static:靜態鏈接,最終生成的 iperf3 可執行文件是包含了 iperf 庫的,strip 后文件大小140多KB,只需要一個文件就可以運行。若不使用 -static 則默認是動態鏈接,生成的 iperf3 可執行文件只有5KB,不包含 iperf 庫,同時 lib 目錄下會額外生成 libiperf.so。更多靜態鏈接和動態鏈接的區別讀者可自行查資料。為了方便拷貝到 Android 設備運行,推薦使用靜態鏈接。
  • -s:去掉編譯產物中不影響執行的信息,如調試信息,符號表等,可以減小庫文件/程序的文件大小。使用和不使用 -s 選項的差別,可以通過 file 命令對比,使用了 -s,file 查看編譯輸出的可執行程序或庫文件的屬性,會有 stripped 標識,未使用 -s 則是 not stripped 標識;並且對比兩種情況的編譯結果,會發現使用 -s 的輸出文件,大小要小得多。

3.4 make 編譯

./configure 正確執行后,就可以執行 make 進行編譯了。

3.4.1 make 可能遇到的問題

1. 編譯報錯:iperf_api.c:function usage: error: undefined reference to 'stderr'

這個問題說起來就比較具體了,和 NDK 的一些歷史問題及版本迭代有關,想要了解更詳細的情況可以參閱 ndk issues #272 和我的另一篇翻譯博客:NDK 中的 Unified Headers。我的解決方法參考了 ndk issues #272 下面的討論,核心的一點就是在 CFLAGS 和 CXXFLAGS 中添加 一個 -D__ANDROID_API__=14 參數。

解決方法:./configure 階段配置如下編譯參數:

  1. CFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s" \
  2. LDFLAGS=-D__ANDROID_API__=14 \
  3. CXXFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s"

2. 編譯報錯:error: undefined reference to '__gnu_mcount_nc'

這個通常也是因為 iperf_profile 的 -pg 編譯參數導致的,解決方法參考上面的本機平台編譯測試一節,在 iperf-3.1.3/src/Makefile 或 iperf-3.1.3/src/Makefile.in 中找到 iperf3_profile_CFLAGS 和 iperf3_profile_LDFLAGS 賦值的地方(第613行左右),去掉 -pg 參數,重新編譯即可。如果讀者參考博客前面的章節做了本機平台編譯測試並解決了相關問題,編譯階段應該是不會再出現這個問題。

3.5 make install 安裝

make 順利完成后,就可以執行 make install,這兩步也可以合並在一起執行:make && make install,這個看個人習慣。make install 完成后,會在 configure 階段 --prefix 指定的目錄下生成編譯結果,其目錄結構如下:

通過 file 命令可以查看到,bin/iperf3 和 lib/libiperf3.so,是 arm 平台的可執行文件和共享庫:

  1. $ file out_install/bin/iperf3
  2. out_install/bin/iperf3: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/, with debug_info, not stripped
  3. $ file out_install/lib/libiperf.so
  4. out_install/lib/libiperf.so: ELF 32-bit LSB pie executable ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /system/, with debug_info, not stripped

4. 用 ndk-build 方式編譯

上面的 ./configure -> make -> make install,這是典型的開源庫編譯方式,比較通用,雖然也適用於Android平台,但是配置工具鏈和 configure 略顯繁瑣。對於Android平台,我們可以使用Android開發者更熟悉的姿勢,即 Android Studio + ndk-build/cmake 的方式,用這種方式充分利用了Android Studio的各種特性,如源碼調用跳轉等,更方便我們閱讀 iPerf3 的源碼。

我們可以直接將 iperf3 源碼解壓到 Android Studio 工程中,接下來的事就都可以在我們熟悉的IDE中進行了。類似這樣:

4.1 生成必要的頭文件

iPerf 源碼中 iperf_config.h 和 version.h 兩個頭文件是由 configure 腳本生成的,所以我們還是要和上面一樣在源碼根目錄執行 ./configure,不過這里可以不用加參數了,因為我們只是用它生成必要的頭文件,不會再用它生成的 Makefile 進行編譯。

$ ./configure 

4.2 配置 ndk-build 編譯腳本

在 jni 目錄 下添加 Android.mkApplication.mk 文件,內容如下:

Android.mk:

  1. LOCAL_PATH := $(call my-dir)
  2. include $(CLEAR_VARS)
  3. LOCAL_MODULE := iperf3
  4. LOCAL_SRC_FILES := iperf-3.1.3/src/cjson.c \
  5. iperf-3.1.3/src/iperf_api.c \
  6. iperf-3.1.3/src/iperf_client_api.c \
  7. iperf-3.1.3/src/iperf_error.c \
  8. iperf-3.1.3/src/iperf_locale.c \
  9. iperf-3.1.3/src/iperf_sctp.c \
  10. iperf-3.1.3/src/iperf_server_api.c \
  11. iperf-3.1.3/src/iperf_tcp.c \
  12. iperf-3.1.3/src/iperf_udp.c \
  13. iperf-3.1.3/src/iperf_util.c \
  14. iperf-3.1.3/src/main.c \
  15. iperf-3.1.3/src/net.c \
  16. iperf-3.1.3/src/tcp_info.c \
  17. iperf-3.1.3/src/tcp_window_size.c \
  18. iperf-3.1.3/src/timer.c \
  19. iperf-3.1.3/src/units.c
  20. # 這3個 t_ 開頭的文件是測試用的,不用包含,否則會有多個main方法入口
  21. # iperf-3.1.3/src/test/t_timer.c \
  22. # iperf-3.1.3/src/test/t_units.c \
  23. # iperf-3.1.3/src/test/t_uuid.c
  24. LOCAL_CFLAGS += -pie -fPIE -fPIC -s
  25. LOCAL_C_INCLUDES += $(LOCAL_PATH)/iperf-3.1.3/src
  26. include $(BUILD_EXECUTABLE)

重要參數解釋:

  • LOCAL_SRC_FILES:規則很簡單,加上源碼目錄中除了 t_ 開始的3個測試文件的其他所有 .c 文件;
  • LOCAL_CFLAGS:為了編譯出合適的 iperf3 可執行文件必要的參數,本文前面或后續章節有解釋;
  • LOCAL_C_INCLUDES:指定頭文件搜索目錄包含iperf源碼目錄。

Application.mk:

  1. APP_PLATFORM := android-21
  2. APP_ABI := armeabi-v7a x86

4.3 ndk-build

在 jni 目錄打開一個終端,執行:ndk-build,編譯完成后 iperf3 可執行文件會輸出到和 jni 同級的 libs 目錄下:

5. 用 CMake 編譯

參考文檔:NDK 入門指南 - CMAKE

用 CMake 編譯的流程如下:

  1. 先執行 cmake,根據 CMakeLists.txt 生成 Makefile 文件;
  2. 然后執行 make 進行編譯。

這里我和上面用 ndk-build 編譯一樣,所有操作都是在 Android Studio 工程的 jni 目錄下進行。

 

5.1 添加 CMakeLists.txt 配置文件

在 Android Studio 工程的 jni 目錄中添加 CMakeLists.txt 文件,內容如下:

  1. cmake_minimum_required(VERSION 3.4.1)
  2.  
  3. #file(GLOB variable [RELATIVE path] [globbing expressions]...)
  4. #GLOB選項將會為所有匹配查詢表達式的文件生成一個文件list,並將該list存儲進變量variable里
  5. file(GLOB IPERF3_C_SOURCES
  6. iperf-3.1.3/src/cjson.c
  7. iperf-3.1.3/src/iperf_api.c
  8. iperf-3.1.3/src/iperf_client_api.c
  9. iperf-3.1.3/src/iperf_error.c
  10. iperf-3.1.3/src/iperf_locale.c
  11. iperf-3.1.3/src/iperf_sctp.c
  12. iperf-3.1.3/src/iperf_server_api.c
  13. iperf-3.1.3/src/iperf_tcp.c
  14. iperf-3.1.3/src/iperf_udp.c
  15. iperf-3.1.3/src/iperf_util.c
  16. iperf-3.1.3/src/main.c
  17. iperf-3.1.3/src/net.c
  18. iperf-3.1.3/src/tcp_info.c
  19. iperf-3.1.3/src/tcp_window_size.c
  20. iperf-3.1.3/src/timer.c
  21. iperf-3.1.3/src/units.c)
  22.  
  23. include_directories(iperf-3.1.3/src)
  24.  
  25. SET(CMAKE_SYSTEM_NAME Android)
  26. # API level
  27. set(CMAKE_SYSTEM_VERSION 21)
  28.  
  29. set(CMAKE_C_FLAGS_RELEASE "-pie -fPIE -fPIC -s")
  30. SET(CMAKE_BUILD_TYPE "Release")
  31.  
  32. add_executable(iperf3 ${IPERF3_C_SOURCES})

5.2 執行 cmake

NDK 通過工具鏈文件支持 CMake。工具鏈文件是用於自定義交叉編譯工具鏈行為的 CMake 文件。用於 NDK 的工具鏈文件位於 NDK 中的 <NDK>/build/cmake/android.toolchain.cmake 內。

由於 cmake 會生成較多編譯配置文件,可以用單獨的目錄保存編譯配置和輸出:

  1. mkdir cmake_build
  2. cd cmake_build
  3. cmake -DCMAKE_TOOLCHAIN_FILE= $NDK/build/cmake/android.toolchain.cmake -DANDROID_ABI="arm64-v8a" ..

cmake 命令需要指定包含 CMakeLists.txt 文件的目錄,我這里是上一級目錄,所以是 ..。同時,cmake 不支持一次指定多個 ABI,如需以多個 Android ABI 為目標,必須為每個 ABI 構建一次。

更多用法參考:NDK 指南 - cmake 命令行

5.3 執行 make

經過上面的 cmake,此時 cmake_build 目錄中已經生成了 Makefile 和其他一些編譯配置文件。此時只需要執行 make,編譯完成后就會在當前目錄下生成 iperf3 可執行文件:

編譯階段到這里也就圓滿結束了~


5. 運行階段

用 adb 將編譯好的 iperf3 可執行文件 push 到手機上有執行權限的目錄(如:/data/local/tmp/)即可運行。但你以為就萬事大吉了嗎? too naive。當你照做的時候,可能新的問題就來了。

5.1 運行可能遇到的問題

  • 運行報錯1:"./iperf3": error: Android 5.0 and later only support position-independent executables (-fPIE)。
  1. $ adb push iperf3 /data/ local/tmp/
  2. iperf3: 1 file pushed, 0 skipped. 252.3 MB/s (216076 bytes in 0.001s)
  3. $ adb shell
  4. HWMHA:/ $ cd /data/local/tmp
  5. HWMHA:/data/ local/tmp $ ls -l iperf3
  6. -rwxrwxrwx 1 shell shell 216076 2020-11-14 11:16 iperf3
  7. HWMHA:/data/ local/tmp $ ./iperf3 -version
  8. "./iperf3": error: Android 5.0 and later only support position-independent executables (-fPIE).

解決方法:這是 Android 5.0 中的一個系統安全特性導致的,參考:Android 5.0 中的安全增強功能。其實報錯內容中就有處理提示,解決方法就是編譯階段在 configure 時在編譯器標識中添加 -pie -fPIE 這兩個選項:

  1. CFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s" \
  2. CXXFLAGS= "-D__ANDROID_API__=14 -pie -fPIE -static -s"

好了,重新編譯,push 到 Android 設備的 /data/local/tmp 下運行:

  1. 1|HWMHA:/data/ local/tmp $ ./iperf3 -version
  2. iperf 3.1.3
  3. Linux localhost 4.9.148 #1 SMP PREEMPT Fri May 22 19:13:52 CST 2020 armv8l
  4. Optional features available: CPU affinity setting, IPv6 flow label, TCP congestion algorithm setting, sendfile / zerocopy, socket pacing

可以打印版本信息了,至少可以運行了嘛,離成功又近了一步。用 iPerf 官網提供的 Public iPerf3 servers 來測試一下,這時候我們又會遇到新問題:

  • 運行報錯2:iperf3: error - unable to create a new stream: No such file or directory。
  • 關聯問題:iperf3: error - unable to create a new stream: Permission denied。
  1. HWMHA:/data/ local/tmp $ ./iperf3 -c bouygues.iperf.fr -p 9200
  2. Connecting to host bouygues.iperf.fr, port 9200
  3. iperf3: error - unable to create a new stream: No such file or directory

解決方法:這個問題和 iperf issue #374 類似,都是因為 iperf 源碼 src/iperf_api.c 中創建臨時文件使用了一個 /tmp/iperf3.XXXXXX 的絕對路徑。/tmp/ 這個路徑在 macOS 和 Linux 中都是存在的,所以不會有問題;但在一般的 Android 系統中是不存在的(一些定制系統除外),所以就會無法創建需要的文件。知道原因后,我們就可以修改一下源碼的 iperf_api.c 文件,在 iperf_new_stream 方法中,將臨時文件的路徑改成一個 Android系統上穩妥存在且有操作權限的路徑,比如:/data/local/tmp。

  1. struct iperf_stream *
  2. iperf_new_stream(struct iperf_test *test, int s)
  3. {
  4. int i;
  5. struct iperf_stream *sp;
  6.  
  7. char template[1024];
  8. if (test->tmp_template) {
  9. snprintf(template, sizeof(template) / sizeof(char), "%s", test->tmp_template);
  10. } else {
  11. // To fix: "error - unable to create a new stream: No such file or directory" runtime error on Android.
  12. // char buf[] = "/tmp/iperf3.XXXXXX";
  13. char buf[] = "/data/local/tmp/iperf3.XXXXXX";
  14. snprintf(template, sizeof(template) / sizeof(char), "%s", buf);
  15. }
  16. // 省略其他代碼...
  17. }

但注意! /data/local/tmp 這個路徑只有在使用 adb shell 時有效,可以用作修改驗證。如果是把 iperf3 可執行文件打包進 APK 然后運行時調用,那么將會遇到 Permission denied 的問題,因為一個普通的 Android 應用進程還是沒有權限訪問 /data/local/tmp 這個目錄的。這種情況就需要將路徑修改為 /data/data/your_package_name/xxx,將 iperf3 可執行文件拷貝到 Android 內部存儲包名下,並添加可執行權限再調用,iperf3 才有完全的執行權限。

  1. // To fix: "error - unable to create a new stream: Permission denied" runtime error on Android.
  2. // char buf[] = "/tmp/iperf3.XXXXXX";
  3. char buf[] = "/data/data/YOUR_PACKAGE_NAME/files/iperf3.XXXXXX";

如果反編譯 iPerf 官網提供 的 he.net Network Tools 這個安卓應用的 APK,可以知道它的包名為:net.he.networktools。查看它 assets 里包含的 iperf 可執行文件的信息,我們會發現這個應用也是用的使用包名內路徑的方法:

  1. $ strings iperf3-pie | grep iperf3.XXXXXX
  2. /data/data/net.he.networktools/cache/iperf3.XXXXXX
  • 運行問題3:執行 iperf3 時,不像執行 ping 命令一樣,能逐步獲得輸出,而是執行完成后才全部返回。

解決方法:在源碼的 iperf_api.c 文件 iprintf 方法中添加iflush() 方法調用:

  1. int iprintf(struct iperf_test *test, const char* format, ...)
  2. {
  3. va_list argp;
  4. int r = -1;
  5.  
  6. if (test->role == 'c') {
  7. if (test->title)
  8. fprintf(test->outfile, "%s: ", test->title);
  9. va_start(argp, format);
  10. r = vfprintf(test->outfile, format, argp);
  11. va_end(argp);
  12.  
  13. /******** fix for Android start ********/
  14. iflush(test);
  15. /******** fix for Android end ********/
  16. }
  17. // 省略...
  18. }

6. Demo:通過可執行文件和 jni 調用方式使用 iperf3

對於 Android 平台在運行時調用 iperf3 可執行文件和用 jni 調用兩種方式,我寫了一個demo供大家參考,GitHub 地址:https://github.com/ChinaStyle812/iPerfDemo-runtime.git 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM