Iperf源代码分析(十)

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: 数据包大小;


你可能感兴趣的:(Iperf源代码分析(十))