如何在RTT计算代码中添加循环,实现10次试验并计算平均RTT?
实现多次RTT测试并计算平均值
问题描述
需要计算客户端与服务器之间n次试验的平均RTT(往返时间),现有一段可计算单次RTT的C语言代码,但不清楚应将代码的哪一部分包裹在循环中,以完成10次RTT测试并计算平均值。当前代码完成一次计算后难以重复测试,可通过终端输入URL和端口号(例如./client www.example.com 80)运行测试。
修改后的完整代码
#include <stdlib.h> #include <string.h> #include <netdb.h> #include <sys/socket.h> #include <arpa/inet.h> #include <unistd.h> #include <sys/time.h> #define RCVBUFSIZE 32 #define TEST_COUNT 10 // 测试次数 void DieWithError(char *errorMessage); int getAddressInfo(const char* host, unsigned short* port, struct sockaddr_in* sock_addr); int main(int argc, char *argv[]) { struct sockaddr_in httpServAddr; unsigned short httpServPort; char *httpRequest = "GET / HTTP/1.1\r\n" // 修正GET后的空格,否则请求无效 "Host: %s\r\n" "Connection: close\r\n\r\n"; const char* host; if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: %s <Server IP/URL> [<HTTP Port>]\n", argv[0]); exit(1); } host = argv[1]; memset(&httpServAddr, 0, sizeof(httpServAddr)); if (getAddressInfo(host, &httpServPort, &httpServAddr) != 0) { DieWithError("Failed to get server address information"); } if (argc == 3) { httpServPort = atoi(argv[2]); } else { httpServPort = 80; } httpServAddr.sin_port = htons(httpServPort); long total_rtt = 0; for (int i = 0; i < TEST_COUNT; i++) { int sock; char httpBuffer[RCVBUFSIZE]; int bytesRcvd, totalBytesRcvd; char request[strlen(httpRequest) + strlen(host) + 1]; // 每次测试重新创建socket并连接 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { DieWithError("socket() failed"); } if (connect(sock, (struct sockaddr *) &httpServAddr, sizeof(httpServAddr)) < 0) { DieWithError("connect() failed"); } sprintf(request, httpRequest, host); if (send(sock, request, strlen(request), 0) != strlen(request)) { DieWithError("send() sent a different number of bytes than expected"); } totalBytesRcvd = 0; printf("=== Test %d Received: ===\n", i+1); struct timeval start, end; gettimeofday(&start, NULL); while ((bytesRcvd = recv(sock, httpBuffer, RCVBUFSIZE - 1, 0)) > 0) { totalBytesRcvd += bytesRcvd; httpBuffer[bytesRcvd] = '\0'; printf("%s", httpBuffer); } gettimeofday(&end, NULL); long rtt = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000; total_rtt += rtt; if (bytesRcvd < 0) { DieWithError("recv() failed"); } printf("\nRound-trip time for test %d: %ld ms\n\n", i+1, rtt); close(sock); // 每次测试结束关闭socket } printf("=== Average RTT over %d tests: %ld ms ===\n", TEST_COUNT, total_rtt / TEST_COUNT); exit(0); } int getAddressInfo(const char* host, unsigned short* port, struct sockaddr_in* httpServAddr) { struct addrinfo hints = {0}; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; struct addrinfo* result; int ret = getaddrinfo(host, NULL, &hints, &result); if (ret != 0) { fprintf(stderr, "getaddrinfo() failed: %s\n", gai_strerror(ret)); return -1; } memcpy(httpServAddr, (struct sockaddr_in*)result->ai_addr, sizeof(struct sockaddr_in)); *port = ntohs(httpServAddr->sin_port); freeaddrinfo(result); return 0; } void DieWithError(char *errorMessage) { perror(errorMessage); exit(1); }
关键修改说明
- 定义
TEST_COUNT常量指定测试次数(这里设为10),用循环包裹完整的socket创建、连接、请求发送、数据接收、RTT计算流程,因为每次测试需要重新建立TCP连接(请求中指定了Connection: close,服务器会在响应后关闭连接)。 - 将
total_rtt变量移到循环外,用于累加每次测试的RTT值,最后计算平均值。 - 修正了原代码中
GET/的错误,改为GET /,否则HTTP请求格式无效,会导致服务器返回错误。 - 每次循环结束后调用
close(sock)关闭当前socket,避免资源泄漏。 - 增加了测试序号的输出,方便区分每次测试的结果。
内容的提问来源于stack exchange,提问作者PikaKirbyBro
相关产品推荐
相关产品推荐

