1.简介
netperf 是一个用于网络性能测试的工具,专门设计来衡量各种类型的网络吞吐量和延迟。它能够在客户端和服务器端进行通信,通过运行不同的测试来评估网络的性能。netperf 常被用于测量 TCP、UDP 等协议的性能,在紫金DPU中用于测试网络性能。TCP_CRR(连接请求响应)测试,是其中的一种测试模式,用于测量在创建和关闭连接时的性能,通常用于模拟短时连接的应用场景。
2.代码解读
2.1 初始化阶段
为消息缓冲区分配内存,分配的大小基于发起端发送的请求(tcp_conn_rr_request)。根据请求中的对齐方式和偏移量设置接收(recv_message_ptr)和发送(send_message_ptr)缓冲区。
netperf_response.content.response_type = TCP_CRR_RESPONSE;
message = (char *)malloc(DATABUFFERLEN);
/* ... */
recv_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->recv_alignment, tcp_conn_rr_request->recv_offset);
send_message_ptr = ALIGN_BUFFER(message, tcp_conn_rr_request->send_alignment, tcp_conn_rr_request->send_offset);
2.2 监听端口等待连接
使用 accept() 接受来自客户端的连接请求,将其分配给 s_data 套接字。如果连接成功,会进入数据传输阶段;如果失败,则返回相应的错误信息并关闭套接字。
s_listen = create_data_socket(local_res);
if (s_listen == INVALID_SOCKET) {
netperf_response.content.serv_errno = errno;
send_response();
exit(1);
}
if (listen(s_listen, 128) == SOCKET_ERROR) {
netperf_response.content.serv_errno = errno;
close(s_listen);
send_response();
exit(1);
}
s_data = accept(s_listen, (struct sockaddr *)&peeraddr_in, &addrlen);
if (s_data == INVALID_SOCKET) {
fprintf(where,"recv_tcp_conn_rr: accept: errno = %d\n",errno);
close(s_listen);
exit(1);
}
2.3 接收请求数据
从客户端接收请求消息,数据存放在 recv_message_ptr 指向的缓冲区中。函数通过 recv() 循环接收数据,直到接收到完整的请求或发生错误。如果接收到的字节数为 0,表示客户端关闭了连接,函数会处理连接关闭并跳出循环。
request_bytes_remaining = tcp_conn_rr_request->request_size;
while (!times_up && (request_bytes_remaining > 0)) {
request_bytes_recvd = recv(s_data, temp_message_ptr, request_bytes_remaining, 0);
if (request_bytes_recvd == SOCKET_ERROR) {
// 处理错误
} else if (request_bytes_recvd > 0) {
request_bytes_remaining -= request_bytes_recvd;
temp_message_ptr += request_bytes_recvd;
} else {
goto bail;
}
}
2.4 发送响应数据
接收到完整的请求后,服务器根据请求中的响应大小,通过 send() 函数将数据发送回客户端。此过程会继续直到传输计数用尽或测试时间结束。
bytes_sent = send(s_data, send_message_ptr, tcp_conn_rr_request->response_size, 0);
if (bytes_sent == SOCKET_ERROR) {
netperf_response.content.serv_errno = 99;
send_response();
exit(1);
}
2.5 关闭连接
每次完成一次请求-响应后,服务器会关闭数据连接 s_data,并准备接收下一个连接。会通过调用 shutdown() 来优雅地关闭连接,确保数据发送完毕。
shutdown(s_data, SHUT_WR);
recv(s_data, recv_message_ptr, 1, 0);
close(s_data);
2.6 计算性能并返回结果
使用 cpu_start() 和 cpu_stop() 记录 CPU 使用情况和测试的运行时间。当测试完成后,服务器会计算传输的总字节数、事务的总数以及消耗的时间,并将这些结果通过 send_response() 返回给客户端。
cpu_start(tcp_conn_rr_request->measure_cpu);
/* ... */
cpu_stop(tcp_conn_rr_request->measure_cpu, &elapsed_time);
tcp_conn_rr_results->bytes_received = (trans_received *
(tcp_conn_rr_request->request_size +
tcp_conn_rr_request->response_size));
tcp_conn_rr_results->trans_received = trans_received;
tcp_conn_rr_results->elapsed_time = elapsed_time;
if (tcp_conn_rr_request->measure_cpu) {
tcp_conn_rr_results->cpu_util = calc_cpu_util(elapsed_time);
}
send_response();
3.测试方法
服务端
netserver
客户端
netperf -t TCP_CRR -H $DST_IP -L $SRC_IP -v 8 -D 10 -l $DURATION -- -r 32,1024 > /tmp/netperf_crr.log 2>&1 &