Iperf发送的数据包结构
在Iperf的测量过程中,说者线程会向听者线程发送一组数据包。在这些数据包中,除了使数据包达到指定大小而使用的填充数据外,还用以下主要信息:
*数据包本身的信息,如编号(id)、发送时间戳(timestamp)。主要用在UDP连接中。
*客户端向服务器端报告所使用的测量参数的信息,服务器端利用这些信息来发起反向连接,这些信息包含在client_hdr结构中。
*听者线程向说者线程报告测量结果的信息,包含在server_hdr结构中。
这些结构定义在文件src/Setting.hpp文件中。Iperf用来保存和操作测试参数的类是Settings,它的定义和实现位于文件src/Settings.hpp和src/Setting.cpp中。
PerfSocket类的成员变量mBuf是指向用来保存数据包的缓冲区的指针(见src/PerfSocket.hpp文件)。
// buffer to do reads/writes char *mBuf;
这里声明mBuf为char型指针,使用时通过强制类型转换将mBuf构造为不同的结构。
UDP_datagram结构用来表示数据包本身的信息,用在UDP通信中,其定义如下(见src/Settings.hpp文件):
// used to reference the 4 byte ID number we place in UDP datagrams // use int32_t if possible, otherwise a 32 bit bitfield (e.g. on J90) struct UDP_datagram { #ifdef HAVE_INT32_T int32_t id; u_int32_t tv_sec; u_int32_t tv_usec; #else signed int id : 32; unsigned int tv_sec : 32; unsigned int tv_usec : 32; #endif };
该结构包括一个32位的id域和用来表明数据包发送时间(timestamp)tv_sec(秒)和tv_usec(微秒)。说者线程在填写这些数据之后将该结构发往对端的听者线程,由后者根据id域的值计算丢包率参数,根据tv_sec和tv_usec计算延迟抖动参数。
客户端通过client_hdr结构向服务器报告使用的连接数据,在双向测试(dualtest和tradeoff)的情况下,服务器依照这些参数发送反向连接。client_hdr的定义如下:
/* * The client_hdr structure is sent from clients * to servers to alert them of things that need * to happen. Order must be perserved in all * future releases for backward compatibility. * 1.7 has flags, numThreads, mPort, and bufferlen */ struct client_hdr { #ifdef HAVE_INT32_T /* * flags is a bitmap for different options * the most significant bits are for determining * which information is available. So 1.7 uses * 0x80000000 and the next time information is added * the 1.7 bit will be set and 0x40000000 will be * set signifying additional information. If no * information bits are set then the header is ignored. * The lowest order diferentiates between dualtest and * tradeoff modes, wheither the speaker needs to start * immediately or after the audience finishes. */ int32_t flags; int32_t numThreads; int32_t mPort; int32_t bufferlen; int32_t mWinBand; int32_t mAmount; #else signed int flags : 32; signed int numThreads : 32; signed int mPort : 32; signed int bufferlen : 32; signed int mWinBand : 32; signed int mAmount : 32; #endif };
****************************************************************************************************************
//flags:表示客户端Iperf的版本信息以及测试模式信息,具体见上述代码中的注释; //numThreads:表示并行的测试线程数,在双向测试中,服务器从收到的第一个数据包中提取出numThreads //的值,来决定发起的并行反向连接的数目; //mPort:客户端使用的端口号,在双向测试中,服务器向客户的这个端口发起反向连接; //bufferlen:反向连接发送的数据包的长度; //mWinBand:TCP协议中表示TCP窗口的大小,UDP协议中表示接收缓冲区的大小; //mAmount:若mAmount>0,则在发送了mAmount字节的数据后说者线程停止发送,若mAmount<0,则在 //发送-mAmount秒后说者线程停止发送。
当使用UDP协议时,由说者(speaker--Client的监控程序)发送给听者(audience--Server的监控程序)的数据包由三部分构成:UDP_datagram结构,用来记录数据包本身的信息;client_hdr结构,用来向服务器告知客户端使用的测试参数;填充数据,可以用用户指定的文件填充,默认情况是用发送方随机填充数据。
对于使用TCP时的情况,由于TCP是面向连接的,TCP提供给上层协议的是数据流模型,没有单独的数据包的概念,因此发送TCP数据时不需要UDP_datagram这样的结构。TCP连接建立后,听者可以通过该链接获知说着的相关信息。说者线程通过write向表示TCP连接的socket一次写入的数据包括两部分:client_hdr结构,用来向服务器告知客户端使用的测试参数;填充数据,可以用用户指定的文件填充,默认情况是用发送方随机填充数据。
client_hdr中各数据域的填充是调用Settings类的方法GenerateClientHdr完成的。GenerateClientHdr方法将结构体ext_gSettings中的相应数据复制到将要发送的client_hdr结构中。
在Iperf中,网络参数的测量主要是由听者线程完成的。当测试结束时,听者线程将测得的数据返回给说者线程。返回测量结果时发送的数据结构是server_hdr:
/* * The server_hdr structure facilitates the server * report of jitter and loss on the client side. * It piggy_backs on the existing clear to close * packet. */ struct server_hdr { #ifdef HAVE_INT32_T /* * flags is a bitmap for different options * the most significant bits are for determining * which information is available. So 1.7 uses * 0x80000000 and the next time information is added * the 1.7 bit will be set and 0x40000000 will be * set signifying additional information. If no * information bits are set then the header is ignored. */ int32_t flags; int32_t total_len1; int32_t total_len2; int32_t stop_sec; int32_t stop_usec; int32_t error_cnt; int32_t outorder_cnt; int32_t datagrams; int32_t jitter1; int32_t jitter2; #else signed int flags : 32; signed int total_len1 : 32; signed int total_len2 : 32; signed int stop_sec : 32; signed int stop_usec : 32; signed int error_cnt : 32; signed int outorder_cnt : 32; signed int datagrams : 32; signed int jitter1 : 32; signed int jitter2 : 32; #endif };
分析上述结构体,我们可以注意到这是服务器端对所产生的数据统计信息结构体,服务器端会将这些信息通过反向连接传回给客户端。那么,在这个结构体中,有这样一些需要注意到的变量:
//flags: 表示服务器Iperf的版本信息以及测试模式信息,具体见上述代码中的注释; //total_len1 && total_len2: 表示的是数据包的长度(具体1和2的区别还在考察中); //stop_sec: 停止时间,以秒为单位; //stop_usec: 停止时间,以微妙为单位; //error_cnt: 错误数; //outorder_cnt: 乱序包数; //datagrams: 数据包大小;