由文章
七,iperf3源代码分析:状态机及状态转换过程—>运行正向TCP单向测试时的服务端代码
八,iperf3源代码分析:状态机及状态转换过程—>运行正向TCP单向测试时的客户端代码
九,iperf3源代码分析:main函数主要流程,正向TCP单向测试时服务端和客户端的交互过程详解
我们知道服务端和客户端配置参数交换过程和状态机变化过程如下(注意:只有iperf3客户端会把配置参数发送给服务端,服务端的参数是不会发送到客户端的):
1、服务端和客户端配置参数交换过程和状态机变化
1)当服务端收到客户端发过来的控制连接建立请求后,就会接收连接请求,并成功的建立连接请求后放在test->ctrl_sck指针里,
2)然后服务端主动进入PARAM_EXCHANGE状态,并给客户端发送PARAM_EXCHANGE指令
3)客户端收到PARAM_EXCHANGE指令后,就开始通过test->ctrl_sck指针指向的控制连接向服务端发送配置参数
4)服务端收到配置参数后,保存并进行配置,进行CREATE_STREAM状态后完成配置参数交换过程
如下图所示左边是客户端,右边是服务端:
2、服务端代码调用过程
iperf_exchange_parameters—>get_parameters—>JSON_read,
通过test->ctrl_sck 控制连接,将接收到的参数解析后,存入test->指针下的各个参数配置项里,完成参数交换。
debug out: set the state from 15 to 9
debug out: func = iperf_exchange_parameters,line = 2087, file = iperf_api.c
debug out: func = get_parameters ,line = 2268, file = iperf_api.c
debug out: func = JSON_read ,line = 2662, file = iperf_api.c
get_parameters:
{
"udp": true,
"omit": 0,
"time": 0,
"num": 8192,
"blockcount": 0,
"parallel": 1,
"len": 1024,
"bandwidth": 1048576,
"pacing_timer": 1000,
"client_version": "3.13"
}
debug out: func = iperf_exchange_parameters,line = 2104, file = iperf_api.c
3、客户端代码调用过程
iperf_exchange_parameters—>send_parameters—>JSON_write
将客户端的参数以JSON的格式,通过test->ctrl_sck 控制连接,将参数发送到服务端。
debug out: receive and change the state from 0 to 9
debug out: func = iperf_exchange_parameters,line = 2082, file = iperf_api.c
debug out: func = send_parameters ,line = 2166, file = iperf_api.c
send_parameters:
{
"udp": true,
"omit": 0,
"time": 0,
"num": 8192,
"blockcount": 0,
"parallel": 1,
"len": 1024,
"bandwidth": 1048576,
"pacing_timer": 1000,
"client_version": "3.13"
}
debug out: func = send_parameters ,line = 2250, file = iperf_api.c
debug out: func = JSON_write ,line = 2635, file = iperf_api.c
4、哪些参数会被客户端同步到服务端
通过send_parameters函数,我们可以看到以下参数会被从客户端发送到服务端:
选项名称 | 配置项 | 保存位置 |
---|---|---|
协议类型TCP/UDP/SCTP | -u 或者–udp或者–sctp | test->protocol->id |
TBD | -o 或者–omit | test->omit |
TBD | -A或者–affinity | test->server_affinity) |
TBD | TBD | test->duration |
TBD | TBD | test->settings->bytes |
TBD | TBD | test->settings->blocks |
TBD | -N, --no-delay | test->no_delay |
TBD | -M, --set-mss | test->settings->mss |
TBD | TBD | test->num_streams |
TBD | -w, --window | test->settings->socket_bufsize) |
TBD | TBD | test->settings->blksize |
TBD | TBD | test->settings->rate |
TBD | –fq-rate | test->settings->fqrate |
TBD | –pacing-timer | test->settings->pacing_timer |
TBD | TBD | test->settings->burst |
TBD | -S, --tos | test->settings->tos |
TBD | -L, --flowlabel | test->settings->flowlabel |
TBD | -T, --title | test->title |
TBD | –extra-data | test->extra_data |
TBD | TBD | test->congestion |
TBD | TBD | test->congestion_used |
TBD | –dont-fragment | test->settings->dont_fragment |
TBD | -Z, --zerocopy | test->zerocopy |
TBD | –repeating-payload | test->repeating_payload |
TBD | TBD | test->settings->rate |
TBD | -R, --reverse, --bidir | test->mode |
TBD | –get-server-output | test->get_server_output |
TBD | –udp-counters-64bit | test->udp_counters_64bit |
具体源代码参见客户端调用的send_parameters和服务端调用的get_parameters二个函数
static int
send_parameters(struct iperf_test *test)
{
int r = 0;
cJSON *j;
PRINTFILEFUNCLINE
j = cJSON_CreateObject();
if (j == NULL) {
i_errno = IESENDPARAMS;
r = -1;
} else {
if (test->protocol->id == Ptcp)
cJSON_AddTrueToObject(j, "tcp");
else if (test->protocol->id == Pudp)
cJSON_AddTrueToObject(j, "udp");
else if (test->protocol->id == Psctp)
cJSON_AddTrueToObject(j, "sctp");
cJSON_AddNumberToObject(j, "omit", test->omit);
if (test->server_affinity != -1)
cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
cJSON_AddNumberToObject(j, "time", test->duration);
cJSON_AddNumberToObject(j, "num", test->settings->bytes);
cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
if (test->settings->mss)
cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
if (test->no_delay)
cJSON_AddTrueToObject(j, "nodelay");
cJSON_AddNumberToObject(j, "parallel", test->num_streams);
if (test->reverse)
cJSON_AddTrueToObject(j, "reverse");
if (test->bidirectional)
cJSON_AddTrueToObject(j, "bidirectional");
if (test->settings->socket_bufsize)
cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
if (test->settings->blksize)
cJSON_AddNumberToObject(j, "len", test->settings->blksize);
if (test->settings->rate)
cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
if (test->settings->fqrate)
cJSON_AddNumberToObject(j, "fqrate", test->settings->fqrate);
if (test->settings->pacing_timer)
cJSON_AddNumberToObject(j, "pacing_timer", test->settings->pacing_timer);
if (test->settings->burst)
cJSON_AddNumberToObject(j, "burst", test->settings->burst);
if (test->settings->tos)
cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
if (test->settings->flowlabel)
cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
if (test->title)
cJSON_AddStringToObject(j, "title", test->title);
if (test->extra_data)
cJSON_AddStringToObject(j, "extra_data", test->extra_data);
if (test->congestion)
cJSON_AddStringToObject(j, "congestion", test->congestion);
if (test->congestion_used)
cJSON_AddStringToObject(j, "congestion_used", test->congestion_used);
if (test->get_server_output)
cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
if (test->udp_counters_64bit)
cJSON_AddNumberToObject(j, "udp_counters_64bit", iperf_get_test_udp_counters_64bit(test));
if (test->repeating_payload)
cJSON_AddNumberToObject(j, "repeating_payload", test->repeating_payload);
if (test->zerocopy)
cJSON_AddNumberToObject(j, "zerocopy", test->zerocopy);
#if defined(HAVE_DONT_FRAGMENT)
if (test->settings->dont_fragment)
cJSON_AddNumberToObject(j, "dont_fragment", test->settings->dont_fragment);
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
/* Send authentication parameters */
if (test->settings->client_username && test->settings->client_password && test->settings->client_rsa_pubkey){
int rc = encode_auth_setting(test->settings->client_username, test->settings->client_password, test->settings->client_rsa_pubkey, &test->settings->authtoken);
if (rc) {
cJSON_Delete(j);
i_errno = IESENDPARAMS;
return -1;
}
cJSON_AddStringToObject(j, "authtoken", test->settings->authtoken);
}
#endif // HAVE_SSL
cJSON_AddStringToObject(j, "client_version", IPERF_VERSION);
if (test->debug) {
char *str = cJSON_Print(j);
printf("send_parameters:\n%s\n", str);
cJSON_free(str);
}
PRINTFILEFUNCLINE
if (JSON_write(test->ctrl_sck, j) < 0) {
i_errno = IESENDPARAMS;
r = -1;
}
cJSON_Delete(j);
}
return r;
}
#----------------------------------------------------------------------------
static int
get_parameters(struct iperf_test *test)
{
int r = 0;
cJSON *j;
cJSON *j_p;
PRINTFILEFUNCLINE
j = JSON_read(test->ctrl_sck);
if (j == NULL) {
i_errno = IERECVPARAMS;
r = -1;
} else {
if (test->debug) {
char *str;
str = cJSON_Print(j);
printf("get_parameters:\n%s\n", str );
cJSON_free(str);
}
if ((j_p = cJSON_GetObjectItem(j, "tcp")) != NULL)
set_protocol(test, Ptcp);
if ((j_p = cJSON_GetObjectItem(j, "udp")) != NULL)
set_protocol(test, Pudp);
if ((j_p = cJSON_GetObjectItem(j, "sctp")) != NULL)
set_protocol(test, Psctp);
if ((j_p = cJSON_GetObjectItem(j, "omit")) != NULL)
test->omit = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "server_affinity")) != NULL)
test->server_affinity = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "time")) != NULL)
test->duration = j_p->valueint;
test->settings->bytes = 0;
if ((j_p = cJSON_GetObjectItem(j, "num")) != NULL)
test->settings->bytes = j_p->valueint;
test->settings->blocks = 0;
if ((j_p = cJSON_GetObjectItem(j, "blockcount")) != NULL)
test->settings->blocks = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "MSS")) != NULL)
test->settings->mss = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "nodelay")) != NULL)
test->no_delay = 1;
if ((j_p = cJSON_GetObjectItem(j, "parallel")) != NULL)
test->num_streams = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "reverse")) != NULL)
iperf_set_test_reverse(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "bidirectional")) != NULL)
iperf_set_test_bidirectional(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "window")) != NULL)
test->settings->socket_bufsize = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "len")) != NULL)
test->settings->blksize = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "bandwidth")) != NULL)
test->settings->rate = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "fqrate")) != NULL)
test->settings->fqrate = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "pacing_timer")) != NULL)
test->settings->pacing_timer = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "burst")) != NULL)
test->settings->burst = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "TOS")) != NULL)
test->settings->tos = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "flowlabel")) != NULL)
test->settings->flowlabel = j_p->valueint;
if ((j_p = cJSON_GetObjectItem(j, "title")) != NULL)
test->title = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "extra_data")) != NULL)
test->extra_data = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "congestion")) != NULL)
test->congestion = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "congestion_used")) != NULL)
test->congestion_used = strdup(j_p->valuestring);
if ((j_p = cJSON_GetObjectItem(j, "get_server_output")) != NULL)
iperf_set_test_get_server_output(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "udp_counters_64bit")) != NULL)
iperf_set_test_udp_counters_64bit(test, 1);
if ((j_p = cJSON_GetObjectItem(j, "repeating_payload")) != NULL)
test->repeating_payload = 1;
if ((j_p = cJSON_GetObjectItem(j, "zerocopy")) != NULL)
test->zerocopy = j_p->valueint;
#if defined(HAVE_DONT_FRAGMENT)
if ((j_p = cJSON_GetObjectItem(j, "dont_fragment")) != NULL)
test->settings->dont_fragment = j_p->valueint;
#endif /* HAVE_DONT_FRAGMENT */
#if defined(HAVE_SSL)
if ((j_p = cJSON_GetObjectItem(j, "authtoken")) != NULL)
test->settings->authtoken = strdup(j_p->valuestring);
#endif //HAVE_SSL
if (test->mode && test->protocol->id == Ptcp && has_tcpinfo_retransmits())
test->sender_has_retransmits = 1;
if (test->settings->rate)
cJSON_AddNumberToObject(test->json_start, "target_bitrate", test->settings->rate);
cJSON_Delete(j);
}
return r;
}