本文目录

这里描述的是iperf3进行单向TCP正向流测试时的iperf3服务端的状态机转换过程,以及转换过程中的代码调用关系。通过前面的iperf3代码主要架构分析之main函数主要流程我们已经知道iperf3虽然是C语言编写的,但它是以面向对象的方式实现的,所以本文中讲述的状态机是以每个测试对象(即为每次测试实例的运行过程创建一个测试对象,从测试开始到测试进行到测试结束输入测试报告管理测试实例的整个生命周期)为单位的。每个测试对象都拥有独立的状态机。所以这里同时也引也客户端和服务端都有自己的独立的状态机,服务端和客户端的状态会通过控制链接相互同步。

一、测试用命令

在正常的测试过程中,使用如下图描述的命令启动iperf3进行单向TCP正向流测试:

  • 服务端
iperf3 -s
  • 客户端
    总共发送8K数据,每次发送1K
iperf3 -c 127.0.0.1 -n 8K -l 1K

二、客户端与服务端测试业务控制流程与状态机交换

在进行TCP业务测试时,客户端与服务端有一个动态的业务控制流程,其中还要同步二侧的状态机,以保证测试业务逻辑的完整性,参照:九,iperf3源代码分析:正向TCP单向测试时服务端和客户端的交互过程详解

三、iperf3服务端状态机中各个状态解析

状态机迁移图

有限状态机编程通常是由当前状态,事件+条件,动作,状态迁移(或称为目标状态)的五元组组成的。所以下面我们也会用这五元组来描述状态。如图所示,iperf3服务端在正常情况下(客户端启动测试后,就一直跑到测试完成,中途不中断测试)有10个状态。状态迁移方向如如箭头所示,状态迁移发生的”事件+条件“由箭头上的字母标识,会在下一章中详细解析。
在这里插入图片描述

初始化状态

服务端开始运行,创建测试对象后,测试对象就直接进入这个状态,这是一个中间状态,测试对象不会一停留在这个状态下。

IPERF_START状态

测试对象创建好后,会开始创建监听端口,并进入监听状态,然后进入到IPERF_START状态下。

PARAM_EXCHANGE状态

在这个状态下,通过控制链接完成客户端和服务端的参数交换,即服务端收取客户端发过过的配置参数。发送create_stream控制消息给客户端,让客户端发起测试|

CREATE_STREAM状态

接收客户端发过来的TCP链接连接建立请求,并创建TCP测试实例。

TEST_START状态

创建TCP测试链接所需要的定时器和各种其它资源

TEST_RUNNING状态

接收处理客户端发过来的TCP数据流,周期性的汇总报告,直到收到客户端发过来的TEST_END指令

TEST_END状态

完成本次测试统计并生成测试报告

EXCHANGE_RESULT状态

等待接收客户端发过来的客户端测试结果报告汇总

DISPLAY_RESULT状态

等待客户端发过来IPERF_DONE指令

IPERF_DONE状态

reset测试对象test, 状态机回到初始化状态,等待下一次测试开始

四、iperf3服务端状态机迁移分析

这一章节描述各个状态下有限状态机迁移五元组源代码调用过程。

K-初始化测试对象(NA—>初始化状态):

服务端开始运行,创建测试对象后,对象状态会直接初始化初始化状态,函数调用关系如下

debug out: func = main                     ,line =   62, file = main.c
debug out: func = iperf_new_test           ,line = 2732, file = iperf_api.c
debug out: set the state from 0

状态机元组名称状态机元组当前值
当前状态
事件+条件perf3做为服务端被启动运行
动作K-初始化测试对象
下一状态初始化状态

A-服务器端测试对象开始运行(初始化状态—>IPERF_START状态):

服务端开始运行,创建测试对象后,读取配置参数并创建服务端监听端口,状态将从 初始化状态 变成 IPERF_START状态

debug out: func = main                     ,line =   62, file = main.c
debug out: func = iperf_new_test           ,line = 2732, file = iperf_api.c
debug out: set the state from 0
-----------------------------------------------------------------------------------
debug out: func = iperf_defaults           ,line = 2796, file = iperf_api.c
debug out: func = iperf_parse_arguments    ,line = 1125, file = iperf_api.c
debug out: func = run                      ,line =  145, file = main.c
debug out: func = iperf_run_server         ,line =  456, file = iperf_server_api.c
debug out: func = iperf_server_listen      ,line =   72, file = iperf_server_api.c
debug out: func = netannounce              ,line =  263, file = net.c
debug out: func = netannounce              ,line =  354, file = net.c
debug out: create listen socket
debug out: set the state from 0 to 15
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态初始化状态
事件+条件进入初始化状态后无条件继续运行
动作A-服务器端测试对象开始运行,创建服务端监听端口
下一状态IPERF_START状态

B-建立控制连接(IPERF_START状态—>PARAM_EXCHANGE状态):

调用select函数,等待并接受客户端发起的控制链接(test->ctrl_sck指向控制链接) 。

......
-----------------------------------------------------------------------------------
debug out: func = iperf_defaults           ,line = 2796, file = iperf_api.c
debug out: func = iperf_parse_arguments    ,line = 1125, file = iperf_api.c
debug out: func = run                      ,line =  145, file = main.c
debug out: func = iperf_run_server         ,line =  456, file = iperf_server_api.c
debug out: func = iperf_server_listen      ,line =   72, file = iperf_server_api.c
debug out: func = netannounce              ,line =  263, file = net.c
debug out: func = netannounce              ,line =  354, file = net.c
debug out: create listen socket
debug out: set the state from 0 to 15
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  498, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  587, file = iperf_server_api.c
debug out: func = iperf_accept             ,line =  154, file = iperf_server_api.c
debug out: set the state from 15 to 9
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态IPERF_START状态
事件+条件收到客户端发起的控制链接连接请求
动作B-建立控制链接
下一状态PARAM_EXCHANGE状态

C-完成服务端与客户端的配置参数交换(PARAM_EXCHANGE状态—>CREATE_STREAM状态):

调用iperf_exchange_parameters函数,接收客户端通过控制链接发送的配置参数,完成服务端与客户端的参数交换 。

......
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  498, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  587, file = iperf_server_api.c
debug out: func = iperf_accept             ,line =  154, file = iperf_server_api.c
debug out: set the state from 15 to 9
-----------------------------------------------------------------------------------
debug out: func = iperf_exchange_parameters,line = 2067, file = iperf_api.c
debug out: func = get_parameters           ,line = 2246, file = iperf_api.c
debug out: set the state from 9 to 10
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态PARAM_EXCHANGE状态
事件+条件收到客户端发送过来的配置参数
动作C-接收并保存客户端送过来的配置参数,并进行配置,并发送create_stream控制消息给客户端,让客户端发起测试
下一状态CREATE_STREAM状态

D-接收客户端发起的TCP测试用连接,并创建新的TCP测试流实例(CREATE_STREAM状态—>TEST_START状态):

在收到客户端发过来的测试链接连接请求后,调用iperf_tcp_accept函数,接收客户端TCP测试链接,并调用iperf_new_stream和iperf_add_stream创建本次新的TCP测试流实例 ,然后将状态设置为TEST_START状态

......
debug out: func = iperf_exchange_parameters,line = 2079, file = iperf_api.c
debug out: func = get_parameters           ,line = 2258, file = iperf_api.c
debug out: func = iperf_exchange_parameters,line = 2096, file = iperf_api.c
debug out: func = iperf_tcp_listen         ,line =  158, file = iperf_tcp.c
debug out: func = iperf_tcp_listen         ,line =  321, file = iperf_tcp.c
debug out: func = iperf_exchange_parameters,line = 2116, file = iperf_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 9 to 10
-----------------------------------------------------------------------------------
debug out: func = iperf_accept             ,line =  164, file = iperf_server_api.c
debug out: func = iperf_on_connect         ,line =  908, file = iperf_api.c
debug out: func = iperf_on_connect         ,line =  928, file = iperf_api.c
debug out: func = iperf_on_connect         ,line =  945, file = iperf_api.c
Accepted connection from 127.0.0.1, port 33578
debug out: func = iperf_on_connect         ,line =  952, file = iperf_api.c
debug out: func = iperf_accept             ,line =  184, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  623, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  828, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  623, file = iperf_server_api.c
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_tcp_accept         ,line =  134, file = iperf_tcp.c
debug out cookie is ql7pfdozixkywwezhwakic2yrvsikowucd7k
debug out: func = iperf_run_server         ,line =  631, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4235, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4447, file = iperf_api.c
[  5] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 33582
debug out: func = iperf_run_server         ,line =  798, file = iperf_server_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 10 to 1
-----------------------------------------------------------------------------------

状态机元组名称状态机元组当前值
当前状态CREATE_STREAM状态
事件+条件收到客户端发送过来的测试链接连接请求
动作D-接收客户端发起的TCP测试用连接,并创建新的TCP测试流实例
下一状态TEST_START状态

E-创建服务端为TCP测试流使用的各种定时器及其它资源(TEST_START状态—>TEST_RUNNING状态):

进入TEST_START状态后,无条件的开始创建 服务端为TCP测试流使用的各种定时器及其它资源,然后进入TEST_RUNNING状态。

......
debug out: func = iperf_run_server         ,line =  631, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  727, file = iperf_server_api.c
debug out: func = iperf_new_stream         ,line = 4235, file = iperf_api.c
debug out: func = iperf_add_stream         ,line = 4447, file = iperf_api.c
[  5] local 127.0.0.1 port 5201 connected to 127.0.0.1 port 33582
debug out: func = iperf_run_server         ,line =  798, file = iperf_server_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 10 to 1
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  803, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  821, file = iperf_server_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 1 to 2
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态TEST_START状态
事件+条件进入TEST_START状态后,无条件开始以下动作
动作E-创建服务端为TCP测试流使用的各种定时器及其它资源
下一状态TEST_RUNNING状态

F-接收TCP测试数据流,直到收到客户端发过来的TEST_END指令(TEST_RUNNING状态—>TEST_END状态):

调用iperf_run_server函数,直接进入TEST_RUNNING分支后,调用iperf_recv函数里的sp->rcv和test->protocol->recv二个函数指针,最终调用iperf_tcp_recv()函数接收客户端发过来的测试数据,并做统计,直到所有测试数据接收处理完毕,并收到客户端通过控制链接发过来的TEST_END控制信息。

......
debug out: func = iperf_run_server         ,line =  803, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  821, file = iperf_server_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 1 to 2
-----------------------------------------------------------------------------------
ebug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  831, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  831, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  831, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  831, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  614, file = iperf_server_api.c
debug out: func = iperf_handle_message_server,line =  209, file = iperf_server_api.c
debug out receive test->state = 4
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态TEST_RUNNING状态
事件+条件进入TEST_RUNNING状态后,无条件开始以下动作
动作F-接收TCP测试数据流,直到收到客户端发过来的TEST_END指令
下一状态TEST_END状态

G-完成本次测试统计并生成测试报告(TEST_END状态—>EXCHANGE_RESULT状态):

从客户端收到TEST_END指令后,通过test->stats_callback(test)和test->reporter_callback(test)二个函数指针,调用iperf_stats_callback和iperf_reporter_callback进行测试结果汇总和生成测试报告

......

debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  831, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  848, file = iperf_server_api.c
debug out: func = iperf_recv               ,line = 1949, file = iperf_api.c
debug out: func = iperf_tcp_recv           ,line =   59, file = iperf_tcp.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  614, file = iperf_server_api.c
debug out: func = iperf_handle_message_server,line =  209, file = iperf_server_api.c
debug out receive test->state = 4
-----------------------------------------------------------------------------------
debug out: func = iperf_stats_callback     ,line = 3232, file = iperf_api.c
debug out: func = iperf_reporter_callback  ,line = 4070, file = iperf_api.c
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-0.00   sec  3.00 KBytes  54.1 Mbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-0.00   sec  3.00 KBytes  54.1 Mbits/sec                  receiver
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 4 to 13
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态TEST_END状态
事件+条件进入TEST_END状态后,无条件开始以下动作
动作G-完成本次测试统计并生成测试报告
下一状态EXCHANGE_RESULT状态

H-完成和客户端的测试结果交互(EXCHANGE_RESULT状态—>DISPLAY_RESULTS状态) :

进入EXCHANGE_RESULT状态后,服务端无条件调用iperf_exchange_result()函数,等待客户端发过来的测试报告后,再进入一下状态。

......

debug out: func = iperf_stats_callback     ,line = 3232, file = iperf_api.c
debug out: func = iperf_reporter_callback  ,line = 4070, file = iperf_api.c
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-0.00   sec  3.00 KBytes  54.1 Mbits/sec                  
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bitrate
[  5]   0.00-0.00   sec  3.00 KBytes  54.1 Mbits/sec                  receiver
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 4 to 13
-----------------------------------------------------------------------------------
debug out: func = iperf_exchange_results   ,line = 2139, file = iperf_api.c
debug out: func = get_results              ,line = 2485, file = iperf_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 13 to 14
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态EXCHANGE_RESULT状态
事件+条件进入EXCHANGE_RESULT状态后,无条件开始以下动作
动作H-完成和客户端的测试结果交互,等待接收客户端发过来的测试报告
下一状态DISPLAY_RESULTS状态

I-等待客户端发过来的IPER_DONE指令(DISPLAY_RESULTS状态—>IPERF_DONE状态):

进入DISPLAY_RESULTS状态后,服务端通过控制链接,调用iperf_handle_message_server()函数,等待客户端发过来的IPERF_DONE指令。

......
debug out: func = iperf_exchange_results   ,line = 2139, file = iperf_api.c
debug out: func = get_results              ,line = 2485, file = iperf_api.c
debug out: func = iperf_set_send_state     ,line = 1810, file = iperf_api.c
debug out: set the state from 13 to 14
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  614, file = iperf_server_api.c
debug out: func = iperf_handle_message_server,line =  209, file = iperf_server_api.c
debug out receive test->state = 16
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态DISPLAY_RESULTS状态
事件+条件进入DISPLAY_RESULTS状态后,无条件开始以下动作
动作I-等待客户端发过来的IPER_DONE指令
下一状态IPERF_DONE状态

J-reset test对象,重新进入初始化流程(IPERF_DONE状态—>初始化状态—>IPERF_START状态):

进入IPERF_DONE状态后,通过run()–>iperf_run_server()–>iperf_reset_test()函数,reset测试对象test,然后无条件运行初始化,建立监听端口,进入到IPERF_START状态,等待下一次测试的开始。

......
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  614, file = iperf_server_api.c
debug out: func = iperf_handle_message_server,line =  209, file = iperf_server_api.c
debug out receive test->state = 16
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = run                      ,line =  165, file = main.c
debug out: func = run                      ,line =  179, file = main.c
debug out: func = iperf_reset_test         ,line = 3065, file = iperf_api.c
#这里已经回到初始化状态,然后无条件运行初始化,建立监听端口,进入到IPERF_START状态,开始新一轮的循环
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态IPERF_DONE状态
事件+条件进入IPERF_DONE状态后,无条件开始以下动作
动作J-reset test对象,重新进入初始化流程
下一状态初始化状态

A-服务器端测试对象开始运行(初始化状态—>IPERF_START状态)::

reset测试对象test后,无条件运行初始化,建立监听端口,进入到IPERF_START状态,等待下一次测试的开始。

......
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  511, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  614, file = iperf_server_api.c
debug out: func = iperf_handle_message_server,line =  209, file = iperf_server_api.c
debug out receive test->state = 16
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  621, file = iperf_server_api.c
debug out: func = iperf_run_server         ,line =  829, file = iperf_server_api.c
debug out: func = run                      ,line =  165, file = main.c
debug out: func = run                      ,line =  179, file = main.c
debug out: func = iperf_reset_test         ,line = 3065, file = iperf_api.c
#这里已经回到初始化状态,然后无条件运行初始化,建立监听端口,进入到IPERF_START状态,开始新一轮的循环
-----------------------------------------------------------------------------------
debug out: func = iperf_run_server         ,line =  467, file = iperf_server_api.c
debug out: func = iperf_server_listen      ,line =   72, file = iperf_server_api.c
debug out: func = netannounce              ,line =  263, file = net.c
debug out: func = netannounce              ,line =  354, file = net.c
debug out: create listen socket
-----------------------------------------------------------
Server listening on 5201 (test #2)
-----------------------------------------------------------
debug out: set the state from 0 to 15
-----------------------------------------------------------------------------------
状态机元组名称状态机元组当前值
当前状态初始化状态
事件+条件进入初始化状态后无条件继续运行
动作A-服务器端测试对象开始运行,创建服务端监听端口
下一状态IPERF_START状态
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐