C用于测量带宽的套接字

C Sockets to Measure Bandwidth

本文关键字:套接字 带宽 测量 用于      更新时间:2023-10-16

作为一项网络练习,我正在尝试编写iPerf的原始版本,以使用C TCP套接字测量网络带宽。我已经设置了套接字代码,以便在客户端和服务器之间建立连接,并将从客户端向服务器发送数据的时间量作为输入。我理解这段代码应该如何在高级别上工作,但在C++中实现它时遇到了困难,特别是在弄清楚如何在结束连接之前通过套接字在设定的时间间隔内发送数据时。我希望客户端打开与服务器的连接,在用户指定的时间间隔内发送数据,然后当这个时间间隔结束时,我希望它向服务器发送一个标志,让它知道数据已经发送完毕,等待服务器确认这个标志,然后计算交换期间的带宽并退出。我希望服务器等待客户端打开连接,接收数据,直到注意到一个表示数据结束的标志,向客户端发送接收到该标志的确认,然后计算带宽并退出。以下是我为客户端/服务器准备的粗略伪代码:

客户:

time = userinput();
host = userinput();
port = userinput();
sockaddr_in address; // set host and port of this
s = socket(AF_INET, SOCK_STREAM, 0); // create TCP socket
connect(s, &address, sizeof(address)); // connect to the user input address

char data[256]; // initialize to all 0's
char finish_flag = 'F'; // send flag to signify data is done being sent
char ack; // buffer to store server's response to the finished_flag
int bytes_sent = 0; // counter for how much data is sent
while (time_interval) {
send(s, data, 256, 0);
bytes_sent += 256;
}
send(s, &finished_flag, 1, 0); // let the server know data is done being sent
recv(s, &ack, 1, MSG_WAITALL); // wait for the server's acknowledgement
bandwidth = (bytes_sent / time_interval); // use actual time socket was open for, not user input time

服务器:

port = userinput();

sockaddr_in address; // set host and port of this
s = socket(AF_INET, SOCK_STREAM, 0); // create TCP socket
listen(s, 1); // listen for 1 connection, the client
int sock = accept(s, &address, sizeof(address)); // accept connection from the client
char data[256]; // buffer to receive data in 
char finish_flag = 'F'; // flag to look for 
char ack; // ack flag to send back to client
int bytes_rec = 0; // counter for how much data is received
while (no finish_flag received) {
recv(sock, &data, 256, MSG_WAITALL);
bytes_rec += 256;
// keep track of time interval somehow
}
send(sock, &ack, 1, 0);
bandwidth = (bytes_rec / time_interval); 

我有设置套接字的工作代码,但在C++中实现发送/接收功能以及如何跟踪服务器和客户端上的时间间隔时,我感到困惑。我不确定我是否应该在C++中查看计时器类,或者是否有一种方法可以设置套接字在设定的时间内发送数据,等等。如果能朝着正确的方向推动,我将不胜感激!

您首先需要的是一个返回当前时间的函数,其粒度足以满足您的测量需求。如果你有,那么你的发送循环可能看起来像这样:

long nowMilliSeconds = myClockFunction();
long sendUntilThisTime = nowMilliseconds + (5*1000);  // stop sending after 5 seconds
while(myClockFunction() < sendUntilThisTime)
{
// send some more data!
}

因此,下一个问题是如何实现myClockFunction()。在较新版本的C++中,我相信std::chrono有一些功能可以使用;或者,如果您愿意,您可以使用POSIX调用,如time(),或其他特定于操作系统的时钟API(取决于您使用的操作系统)。

至于接收端,你的接收代码需要知道它何时接收到所有数据——但如果你的完成标志只有一个字节长,而你的接收器总是在等待接收256字节的块,那么你就有问题了——你的发送器会发送完成标志,你的接收器会收到它,但是将继续等待其他255个字节,并且因此将永远不会发回任何响应。最简单的解决方案是使完成标志也有256字节长;那么接收器可以像现在一样工作,只是在接收到每个256字节的缓冲区之后,它会检查缓冲区的内容,看看这个缓冲区是代表完成标志还是只是正常的测试数据。或者,您可以让接收器一次只读取一个字节,而不是256个字节,但这会降低效率,因为它必须更频繁地调用recv()256次。