10. iperf3 ソース コード分析: iperf3 -P マルチ接続並列テスト TCP マルチストリーム作成管理使用リリース プロセス


iPerf3 -P パラメータの詳細なグラフィック分析 を通じて 、次の 2 つのケースでは、-P パラメータを使用してテスト パラメータを最適化し、最も正確なネットワーク テスト結果を達成できることがわかりました。

  1. テスト: 「クライアントとサーバー間の複数の接続」のテスト シナリオ
  2. TCP の受信ウィンドウと送信ウィンドウが小さすぎるため、ネットワーク帯域幅を十分に活用できません

最初のシナリオは、-P パラメーターを使用する標準的なシナリオです。2 番目のシナリオでは、通常、ネットワーク帯域幅を最大限に活用するために、-W パラメーターを通じて TCP 受信ウィンドウと送信ウィンドウのサイズを調整する必要があります。この記事では、「iperf3 -P マルチ接続フロー並列テスト」のシナリオで、クライアント側と受信側で iperf3 が複数接続の送受信パケット テスト プロセスを管理および処理する方法について説明します。

以下の記事から、ステート マシンの遷移とコード呼び出しの主要なプロセスを分析しました。

1. 全体的なコード構造とビジネスプロセス

一般に:

1.1. サーバーの場合:

  1. 作成プロセス:
    CREATE_STREAM 状態に入ると、iperf3 サーバーはまず iperf_accept()—>iperf_tcp_accept() を呼び出して、クライアントから送信されたテスト TCP 接続確立要求を受信した後、テスト接続テスト ストリームを確立し、次に iperf_new_stream()— を呼び出します。 >iperf_init_stream()—>iperf_add_stream() は、現在のテスト接続テスト ストリームを作成し、テスト インスタンスに追加します。このテスト接続テスト ストリームは -P パラメータの設定に依存し、1 つ以上の が存在する可能性があることに注意してください。

  2. 管理と使用プロセス:
    TEST_RUNNING 状態に入ると、iperf3 サーバーは select を使用してすべてのテスト接続テスト ストリームをポーリングし、テスト データを受信した est ストリームのすべてのソケットで iperf_recv()—>iperf_tcp_recv() を呼び出します。データを取得し、テスト結果の統計を作成します。クライアントから送信された TEST_END コマンドを受信するまで、TEST_END 状態になります。

  3. 解放プロセス:
    IPERF_DONE 状態に入った後、iperf3 サーバーは iperf_reset_test()—>iperf_free_stream() を呼び出してすべてのテスト接続テスト ストリームを走査し、すべてのテスト ストリームが解放されるまでテスト接続テスト ストリームを 1 つずつ解放します。

1.2. クライアントの場合:

  1. 作成プロセス:
    サーバーによって送信された CREATE_STREAM コマンドを受信した後、サーバーは CREATE_STREAM 状態に入り、iperf3 クライアントは積極的に TCP 接続確立要求を開始し、すべてのテスト接続テスト ストリームが正常に確立されるまで iperf_new_stream、iperf_init_stream、iperf_add_stream を呼び出します。電話を切る テスト インスタンスに移動し、テスト リンクのテスト ストリームが -P パラメータの設定に依存し、1 つ以上の が存在する可能性があることに注意してください。

  2. 管理と使用プロセス:
    サーバーから送信された TEST_RUNNING コマンドを受信して​​ TEST_RUNNING 状態に入った後、iperf3 クライアントはすべてのテスト接続テスト ストリームをポーリングし、iperf_send—iperf_tcp_send を呼び出して各ストリームでテスト データを送信し、テスト結果の統計を作成します。テストが完了するまで。

  3. 解放プロセス:
    IPERF_DONE 状態に入った後、iperf3 クライアントは iperf_free_test—iperf_free_stream を呼び出してすべてのテスト接続テスト ストリームを走査し、すべてのテスト ストリームが解放されるまでテスト接続テスト ストリームを 1 つずつ解放します。

2. データ構造分析:

テスト ストリームはテスト構造の下のポインタです。このポインタは一方向リストを指し、現在のテスト インスタンスの下で 1 つ以上のテスト ストリームを管理します。各テスト ストリームは TCP テスト接続に対応します。


struct iperf_test
{
    
    
    char      role;                             /* 'c' lient or 's' erver */
    enum iperf_mode mode;
    ......										//此处省略很多代码
    SLIST_HEAD(slisthead, iperf_stream) streams;//这里通过SLIST_HEAD这个宏定义了指向test->streams的单列表指针
    SLIST_HEAD(plisthead, protocol) protocols;
    ......										//此处省略很多代码
};

このとき、SLIST_HEADのマクロ展開後の struct slisthead {struct iperf_stream *slh_first;} ストリームでは、struct slisthead 型の変数 streams が定義されており、この変数のメンバは struct iperf_stream 型のポインタ slh_first の 1 つだけです。streams.slh_firstを通じてアクセス
できます。

3. いくつかの重要な管理機能と期間機能分析:

3.1. サーバーの場合:

  1. 作成プロセス:
    iperf_run_server()—>iperf_tcp_accept()
    iperf_run_server()—>iperf_new_stream()—>iperf_init_stream()—>iperf_add_stream() は、
    クライアントによって開始された TCP 接続を受け入れ、各 TCP 接続インスタンスを開始して保存します。

  2. 管理および使用プロセス:
    iperf_run_server()—>iperf_recv()—>iperf_tcp_recv()、各 TCP 接続をクエリし、受信したデータがある場合は iperf_tcp_recv() を呼び出して接続上のすべてのデータを受信します。

  3. 解放プロセス:
    run()—>iperf_reset_test()—>iperf_free_stream()、テスト オブジェクトをリセットし、すべてのテスト接続を解放し、次のテストの開始を待ちます。

3.2. クライアントの場合:

  1. 作成プロセス:
    iperf_create_streams()—>create_socket()—>iperf_new_stream()—>iperf_init_stream()—>iperf_add_stream() iperf_create_streams を
    呼び出した後、create_socket をループしてサーバーへの TCPI テスト接続を開始し、TCP テスト接続インスタンスを作成します。各 TCP テスト接続はインスタンスに対応し、単一テーブル形式で test->streams.slh_first に保存されます。

  2. 管理および使用プロセス:
    iperf_run_client()—>iperf_send()—>iperf_tcp_send()、このテストが終了するまで、各 TCP テスト接続でデータを周期的に送信します。

  3. 解放プロセス:
    main()—>iperf_free_test()—>iperf_free_stream() このテストが完了したら、main 関数に戻り、解放を開始します。

4. リストの管理に使用されるマクロ:

リスト管理用のマクロはすべて queue.h ファイルに配置されており、主に test->streams.slh_first のユニットリストの初期化、追加、削除、解放、検索、走査などの操作を実行します。次の抜粋はコードの一部であり、コードを読む際の参考として使用できるコメントが付けられています。

/*
 * Singly-linked List definitions.
 */
 // 定义一个单列表变量指针
#define SLIST_HEAD(name, type)						\
struct name {
      
      								\
	struct type *slh_first;	/* first element */			\
}

#define	SLIST_HEAD_INITIALIZER(head)					\
	{
      
       NULL }

#define SLIST_ENTRY(type)						\
struct {
      
      								\
	struct type *sle_next;	/* next element */			\
}
/*
 * Singly-linked List access methods.
 */
 //查找单列表头结点
#define	SLIST_FIRST(head)	((head)->slh_first)
#define	SLIST_END(head)		NULL
#define	SLIST_EMPTY(head)	(SLIST_FIRST(head) == SLIST_END(head))
#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)

//遍历单列表
#define	SLIST_FOREACH(var, head, field)					\
	for((var) = SLIST_FIRST(head);					\
	    (var) != SLIST_END(head);					\
	    (var) = SLIST_NEXT(var, field))

#define	SLIST_FOREACH_PREVPTR(var, varp, head, field)			\
	for ((varp) = &SLIST_FIRST((head));				\
	    ((var) = *(varp)) != SLIST_END(head);			\
	    (varp) = &SLIST_NEXT((var), field))

/*
 * Singly-linked List functions.
 */
 //初始化一个列表
#define	SLIST_INIT(head) {
      
      						\
	SLIST_FIRST(head) = SLIST_END(head);				\
}

5. 実行プロセスの分析

5.1. サーバーの場合:

  1. 作成プロセス:
    iperf_run_server()—>iperf_tcp_accept()
    iperf_run_server()—>iperf_new_stream()—>iperf_init_stream()—>iperf_add_stream() は、
    クライアントによって開始された TCP 接続を受け入れ、各 TCP 接続インスタンスを開始して保存します。通話ログは次のとおりです。
iperf3 -s
......
debug out: func = iperf_run_server         ,line =  625, file = iperf_server_api.c
debug out: func = iperf_tcp_accept         ,line =  123, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: add stream 1
[  5] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 56288
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  625, file = iperf_server_api.c
debug out: func = iperf_tcp_accept         ,line =  123, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: add stream 3, i = 3
[  8] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 56292
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  625, file = iperf_server_api.c
debug out: func = iperf_tcp_accept         ,line =  123, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: search stream 3, i = 4
debug out: add stream 4, i = 4
[ 10] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 56304
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  625, file = iperf_server_api.c
debug out: func = iperf_tcp_accept         ,line =  123, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: search stream 3, i = 4
debug out: search stream 4, i = 5
debug out: add stream 5, i = 5
[ 12] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 56314
---------------------------------------------------------------------------------------


  1. 管理および使用プロセス:
    iperf_run_server()—>iperf_recv()—>iperf_tcp_recv()

以下に示すように Log を呼び出して各 TCP 接続をクエリし、受信したデータがある場合は iperf_tcp_recv() を呼び出して接続上のすべてのデータを受信します。

iperf3 -s
......
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1951, file = iperf_api.c
debug out: current sp->id =1 
debug out: current sp->id =3 
debug out: current sp->id =4 
debug out: current sp->id =5 
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1951, file = iperf_api.c
debug out: current sp->id =1 
debug out: receiving at sp->id =1 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =3 
debug out: current sp->id =4 
debug out: current sp->id =5 
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1951, file = iperf_api.c
debug out: current sp->id =1 
debug out: current sp->id =3 
debug out: receiving at sp->id =3 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =4 
debug out: receiving at sp->id =4 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =5 
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1951, file = iperf_api.c
debug out: current sp->id =1 
debug out: receiving at sp->id =1 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =3 
debug out: receiving at sp->id =3 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =4 
debug out: current sp->id =5 
debug out: receiving at sp->id =5 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
---------------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1951, file = iperf_api.c
debug out: current sp->id =1 
debug out: current sp->id =3 
debug out: current sp->id =4 
debug out: receiving at sp->id =4 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: current sp->id =5 
debug out: receiving at sp->id =5 
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
---------------------------------------------------------------------------------------
  1. 解放プロセス:
    run()—>iperf_reset_test()—>iperf_free_stream()
debug out: func = run                      ,line =  179, file = main.c
debug out: func = iperf_reset_test         ,line = 3072, file = iperf_api.c
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 1
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 3
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 4
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 5

5.2. クライアントの場合:

  1. 作成プロセス:
    iperf_create_streams()—>create_socket()—>iperf_new_stream()—>iperf_init_stream()—>iperf_add_stream() iperf_create_streams を
    呼び出した後、create_socket をループしてサーバーへの TCPI テスト接続を開始し、TCP テスト接続インスタンスを作成します。各 TCP テスト接続はインスタンスに対応し、単一テーブル形式で test->streams.slh_first に保存されます。
debug out: func = iperf_create_streams     ,line =   69, file = iperf_client_api.c
debug out: func = create_socket            ,line =  129, file = net.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: add stream 1
[  5] local 127.0.0.1 port 56288 connected to 127.0.0.1 port 5201
debug out: func = create_socket            ,line =  129, file = net.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: add stream 3, i = 3
[  7] local 127.0.0.1 port 56292 connected to 127.0.0.1 port 5201
debug out: func = create_socket            ,line =  129, file = net.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: search stream 3, i = 4
debug out: add stream 4, i = 4
[  9] local 127.0.0.1 port 56304 connected to 127.0.0.1 port 5201
debug out: func = create_socket            ,line =  129, file = net.c
debug out: func = iperf_new_stream         ,line = 4247, file = iperf_api.c
debug out: func = iperf_init_stream        ,line = 4398, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4461, file = iperf_api.c
debug out: search stream 1, i = 3
debug out: search stream 3, i = 4
debug out: search stream 4, i = 5
debug out: add stream 5, i = 5
[ 11] local 127.0.0.1 port 56314 connected to 127.0.0.1 port 5201

  1. 管理および使用プロセス:
    iperf_run_client()—>iperf_send()—>iperf_tcp_send()
    ループは、このテストが終了するまで各 TCP テスト接続でデータを送信します。
debug out: func = iperf_run_client         ,line =  633, file = iperf_client_api.c
debug out: func = iperf_send               ,line = 1890, file = iperf_api.c
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 1
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 3
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 4
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 5
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 1
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 3
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 4
debug out: func = iperf_send               ,line = 1907, file = iperf_api.c
debug out: func = iperf_tcp_send           ,line =   87, file = iperf_tcp.c
debug out: sending at sp->id = 5

  1. 解放プロセス:
    main()—>iperf_free_test()—>iperf_free_stream() このテストが完了したら、main 関数に戻り、解放を開始します。
iperf Done.
debug out: func = main                     ,line = 121,  file = main.c
debug out: func = iperf_free_test          ,line = 2940, file = iperf_api.c
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 1
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 3
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 4
debug out: func = iperf_free_stream        ,line = 4222, file = iperf_api.c
debug out: free stream 5

おすすめ

転載: blog.csdn.net/meihualing/article/details/129473793