Iperf 2.x客户端如何检测它发送的流量?

问题描述:

如果一个执行例如iperf -c 178.62.60.141 -fm -b 100m -u -t 30 -i 10,然后每间隔10秒后,客户端的Iperf打印出它在mebibytes已经传送的数据量:Iperf 2.x客户端如何检测它发送的流量?

[email protected]:~# iperf -c 178.62.60.141 -fm -b 100m -u -t 30 -i 10 
WARNING: option -b implies udp testing 
------------------------------------------------------------ 
Client connecting to 178.62.60.141, UDP port 5001 
Sending 1470 byte datagrams 
UDP buffer size: 0.22 MByte (default) 
------------------------------------------------------------ 
[ 3] local 146.185.187.148 port 37660 connected with 178.62.60.141 port 5001 
[ ID] Interval  Transfer  Bandwidth 
[ 3] 0.0-10.0 sec 119 MBytes 100 Mbits/sec 
[ 3] 10.0-20.0 sec 119 MBytes 100 Mbits/sec 
[ 3] 20.0-30.0 sec 119 MBytes 100 Mbits/sec 
[ 3] 0.0-30.0 sec 358 MBytes 100 Mbits/sec 
[ 3] Sent 255661 datagrams 

同样如此TCP。实际上,传输的数据和带宽在之后打印出,并且传输的数据有时会比“-b”标志指定的带宽多一些或少一些,这应该意味着Iperf客户端实际上以某种方式对发送的数据进行计数并不仅仅打印“-b”(带宽)标志的参数。但是,Iperf客户端如何计算它发送的数据量?它肯定不会在低级别上执行此操作,因为如果我在tc中引入了10%的数据包丢失,请执行iperf -c 178.62.60.141 -fm -b 100m -u -t 30 -i 10,然后比较Iperf客户端认为它发送的数据包(来自Iperf客户端输出)与实际连接到数据包的数据量从ip -s link show dev eth0输出),然后Iperf客户端认为它发送了大于250k的数据报,而实际上它只是超过了230k。如果我用tc令牌桶过滤器排队纪律来监视流量,也就是说,根据Iperf客户端,它已经以100Mbps发送流量,而实际流量由警察监管,所以这同样适用。

如果我尝试分析Iperf的源代码(http://ftp.de.debian.org/debian/pool/main/i/iperf/iperf_2.0.5.orig.tar.gz),那么据我了解,客户端连接使用常规connect()系统调用在src目录下的Client.cpp文件中编码?我想报告是在Reporter.c文件中编写的,但是对于我来说这太复杂了。有人可以解释(代码示例)Iperf 2.x客户端如何检测它发送的流量?

在查看源代码之前,这看起来相当简单。客户应该知道它发送了多少东西。毕竟,它发送了它。因此,它必须查看系统时钟,获取发送给定数量的数据所需的时间,并计算出速率。

而且,现在已经看到了Reporter.c--正如预期的那样,存在各种各样的gettimeofday()系统调用,它们捕获系​​统时钟的值。

此实用程序发送的流量不能是如此大的谜团。毕竟,它发送了它,所以它应该知道有多少。

+0

我也注意到'Reporter.c'和'Client.cpp'文件中的'gettimeofday()'函数,但我不明白在什么时间发生。也许这只是我,但代码本身也看起来有点模糊。我也希望发送UDP数据报是使用'write()'函数完成的,并且在发送数据到套接字之前和之后调用'gettimeofday()'完成带宽测量,但是我希望从中获得相应的代码片段Iperf源代码。 – Martin 2014-09-04 10:45:45

您可以追踪写入总金额的send(), write() or *printf()的返回值......然后每X时间打印一次(当前 - 最后一次),然后最后设置为当前值。

在iperf的,这是通过调用做int iperf_tcp_send()(对于UDP类似功能)

的返回值write(), send() and the *printf()功能是写入的字符数。如果你在不使用返回值的情况下使用这些函数,那么以(void)作为前缀是明智的,但是我看到很多代码忽略了它,导致许多程序员认为它们是无效函数。

此外,写入调用并不保证发送所有数据,所以返回值对于确保完整写入整个缓冲区是非常有用的。看这个检查的一个很好的例子Rob Landley's Toybox implementation of writeall()