IPerf——网络测试工具介绍与源码解析(2)
对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序实现的过程能够起到事半功倍的效果。
IPerf主要分为如下几个模块:
- 选项参数处理;
- 线程封装和角色扮演;
- 四种线程模式(或者说角色):
- 客户端线程;
- 服务端线程;
- 报告者线程;
- 监听者线程。
- 四种线程模式(或者说角色):
- 套接字选项设置与提取;
- 链表和数组的封装和维护;
- 处理多并发Condition条件变量的封装;
- 时间戳封装;
- Windows下作为后台服务运行的创建和运行。
下面尽可能针对每个模块进行说明:
选项参数的处理:
作为命令行控制台应用程序,首要考虑到的问题就是对输入参数命令行选项的处理,如果是简单的应用程序直接通过case-switch或者if条件语句或许可以解决,但是一旦到了规模较大,实现内容较为复杂的控制台应用程序,比如IPerf,还是用该处理方法就显得相对笨拙,在性能、逻辑处理等方面都有所不及。
对于选项参数的处理,IPerf使用的GUN的一个getopt文件,在Linux下已有该头文件,而在Windows需要自己导入该头文件和实现文件,加入文件之后,还需要做的就是对文件中的一些长选项和短选项字符串进行处理,因为这是自己定义的需求,处理选项参数的逻辑是一定的,但是要将哪些内容作为合理的选项和参数以及操作数,那些又是非法的字符和未能识别的操作数,程序需要据此进行判断,所以需要进行一个初始化的过程,后面在使用的过程中调用相应的接口对主函数传进来的args和argv[]作为输入参数进行处理就行了,更多关于选项参数的处理,可以看看该篇文章,或者自行网上找寻。
程序的主要模块就是角色线程的生成、运行和销毁,其他模块包括时间戳、条件变量、维护的链表等都是为此服务的,所以这里打算先说一下其他模块然后在逐一分析不同类型的线程。
套接字选项的封装和设置:
说套接字选项之前还需要先说一下套接字的生成,IPerf对套接字Socket的生成定义了一个名为WIN32Socket的宏,这个宏内部调用了WSASocket,而套接字的属性和协议类型是通过定义WSAPROTOCOL_INFO类型静态函数,并将该函数作为输入参数传到WASSocket实现的。
PerfSocket.cpp中只有一个名为SetSocketOptions的函数,顾名思义就是用来设置套接字选项的值,函数里面包含设置TCP滑动窗口大小(setsock_tcp_windowsize函数在另一个名为tcp_window_size.c的文件中单独实现)、设置拥塞控制、设置多播、设置IP服务类型(这个很少用得到)、设置最大报文段大小(setsock_tcp_mss函数在sockets.c文件中实现)、设置非延迟等。当然,除了设置套接字选项外,也有获取相应选项的函数,比如getsock_tcp_windowsize和getsock_tcp_mss。
在SocketAddr.c文件中,IPerf定义了一系列以“SocketAddr_函数功能”格式命名的函数,通过宏条件判断是否支持IPV6,定义了包括:通过IP地址获取到或者说转换成对端的套接字地址结构,将网络序转成点分十进制,获取和设置端口值等,围绕着定义的iperf_sockaddr类型(IPV4下为sockaddr_in类型,IPV6下为sockaddr_storage)判断该套接字地址是否相同等。
链表和数组的维护和封装:
IPerf在实现中创建了几种不同类型的链表和数组:在开始时的线程链表,报告使用的报告者首部链表,监听(者)线程维护的客户端链表,紧接在传送类型报告者首部后面的包数组,在服务端和多并发客户端维护的多组报告首部维护的传输信息数组。具体的接下来会详细讲述到,List.cpp封装对Iperf_ListEntry类型链表的增删查和销毁操作,而该链表仅是监听者用来存储和维护已连接客户端的信息,别无它用。
处理多并发Condition条件变量的封装:
Condition是IPerf自己封装的结构体,变量mCondition为事件内核对象的句柄,变量mMutex为互斥量的句柄,
Condition_Initialize( Cond ): 创建一个初始化就处于触发状态的互斥量并把返回的句柄值赋予mMutex,创建一个初始化为未触发状态的手动重置事件并把返回的句柄值赋予mCondition;
Condition_Destroy( Cond ):通过mCondition和mMutex的句柄值销毁事件内核对象和互斥量;
Condition_Lock( Cond ) == Mutex_Lock( &Cond.mMutex ) == WaitForSingleObject( Cond.mMutex, INFINITE )
Condition_Unlock( Cond ) == Mutex_Unlock( &Cond.mMutex ) == ReleaseMutex( Cond.mMutex )
Condition_Wait( Cond ): 首先释放互斥量,接着阻塞永久等待事件发生,然后等待互斥量;
Condition_TimedWait( Cond ): 首先释放互斥量,接着阻塞在一定的时间内等待事件发生,然后等待互斥量;
Condition_Signal( Cond ):因为是手动重置事件,当其被调用时,所有正在等待该事件的线程都会变成可调度状态;首先需要了解SetEvent和PulseEvent的区别,因为是手动重置事件,这对于两个函数就有区别了,在自动重置事件类型下事件发生后被等待接收后会自动重置为未触发状态,具体可以查看《Windows核心编程》第9章的内容,里面还介绍了SignalObjectAndWait函数的作用呢。
Condition条件变量定义的宏在使用过程中自己是不太理解的,因为调用的时候容易将等待事件和获取互斥量相互混淆,明明刚释放了互斥量然后永久等待事件发生时,好不容易等到事件发生了又要获取互斥量的所有权,所以写者在每次等待和每次进入以及随后的退出Condition时都加了相应的Debug输出,这样或许能够容易理解点,因为时间的关系,只能将这事放到后面去啃明白,但是在输出的过程中确实能发现其起到的作用,比如报告者在无可奉告的情况下等待输出内容的产生。
时间戳:
估计为了与UNIX统一起来,IPerf在Win32上不是直接调用API使用时间,而是自己封装了gettimeofday,先通过GetSystemTimeAsFileTime获取的UTC格式的时间转换成UNIX新纪元下的时间并通过timeval类型进行返回,在该实现函数中使用了几个特殊的数字,这在源代码行上的注释已经说明清楚,这里不再讲述;
TimeStamp这个类中就只有一个类型为timeval的成员变量,成员函数包括获取当前的时间,对时间进行相加减,比较两个时间的先后等,比较容易理解。
时间戳主要用在数据传输过程中给每个发送包赋值,表明这个包发送的时间;还有在-i选项在使用的条件下,计算每次需要打印报告的时间,通过比较将要打印报告的时间和最新发送包的时间戳,决定是否打印这段时间发送的带宽和发送的数据量以及发送的时间段。
作为后台服务运行:
仅用于服务端,并且在作为后台服务运行时,-o filename 选项参数才能起到作用,同样也是加入他人实现的文件,稍微看了一下,是通过SCManager的API才创建和执行服务的,这个后面有时间再认真学习,可以考虑自己在后面的某些项目中可以复用。
本文暂且就讲到这里,下一篇开始讲解线程和角色,也就是结合着线程讲解客户端、服务端、报告者、监听者的执行过程,暂且仅在TCP模式下,UDP后续再来说明,当然理解了TCP模式下的运行逻辑后,相信UDP模式下也不难理解。
IPerf——网络测试工具介绍与源码解析(2)的更多相关文章
- IPerf——网络测试工具介绍与源码解析(4)
上篇随笔讲到了TCP模式下的客户端,接下来会讲一下TCP模式普通场景下的服务端,说普通场景则是暂时不考虑双向测试的可能,毕竟了解一项东西还是先从简单的情况下入手会快些. 对于服务端,并不是我们认为的直 ...
- IPerf——网络测试工具介绍与源码解析(1)
IPerf是一个开源的测试网络宽带并能统计并报告延迟抖动.数据包丢失率信息的控制台命令程序,通过参数选项可以方便地看出,通过设置不同的选项值对网络带宽的影响,对于学习网络编程还是有一定的借鉴意义,至少 ...
- IPerf——网络测试工具介绍与源码解析(3)
[线程的生成] 生成线程时需要传入一个thread_Settings类型的变量,thread_Settings包含所有线程运行时需要的信息,命令行选项参数解析后所有得到的属性都存储到该类型的变量中 ...
- IPerf——网络测试工具介绍与源码解析(5)
本篇随笔讲述一下TCP协议下,双向测试模式和交易测试模式下客户端和服务端执行的情况: 双向测试模式: 官方文档的解释 Run Iperf in dual testing mode. This will ...
- Android IntentService使用介绍以及源码解析
版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.IntentService概述及使用举例 IntentService内部实现机制用到了HandlerThread,如果对HandlerThrea ...
- vue系列---Mustache.js模板引擎介绍及源码解析(十)
mustache.js(3.0.0版本) 是一个javascript前端模板引擎.官方文档(https://github.com/janl/mustache.js) 根据官方介绍:Mustache可以 ...
- JUC中Lock和ReentrantLock介绍及源码解析
Lock框架是jdk1.5新增的,作用和synchronized的作用一样,所以学习的时候可以和synchronized做对比.在这里先和synchronized做一下简单对比,然后分析下Lock接口 ...
- 【转载】Android IntentService使用全面介绍及源码解析
一 IntentService介绍 IntentService定义的三个基本点:是什么?怎么用?如何work? 官方解释如下: //IntentService定义的三个基本点:是什么?怎么用?如何wo ...
- Android HandlerThread使用介绍以及源码解析
摘要: 版权声明:本文出自汪磊的博客,转载请务必注明出处. 一.HandlerThread的介绍及使用举例 HandlerThread是什么鬼?其本质就是一个线程,但是Han ...
随机推荐
- Linux文件权限与属性详解 之 一般权限
目录 一般属性 1. iNode: 3152621 2. 文件类型 3.文件访问权限 4. 链接数目: 5. 文件所有者 6. 文件所属组 7. 文件大小 8. 修改时间 9. 文件名称 Linux文 ...
- 部署vmware-vcsa 6.5
介绍一下vcsa vsphere的两个最重要的组件是esxi和vcenter server,esxi是虚拟化主机管理软件,而vcenter server则是管理.组织多台esxi主机的管理中心. es ...
- Django 系列博客(七)
Django 系列博客(七) 前言 本篇博客介绍 Django 中的视图层中的相关参数,HttpRequest 对象.HttpResponse 对象.JsonResponse,以及视图层的两种响应方式 ...
- 使用VSCode如何调试C#控制台程序_2_加深总结
要想使用调试,必须创建项目 1-你要调式的类,控制台类等等,你需要放在一个项目下,这个项目最好是由使用.net core创建的,VSCode对应的命令为: dotnet new console(这里以 ...
- ls 指令的介绍
每个文件在linux下面都会记录许多的时间参数, 其实是有三个主要的变动时间,那么三个时间的意义是什么呢? modification time (mtime) : 当该文件的“内容数据”变更时,就会更 ...
- python学习笔记(二)、字符串操作
该一系列python学习笔记都是根据<Python基础教程(第3版)>内容所记录整理的 1.字符串基本操作 所有标准序列操作(索引.切片.乘法.成员资格检查.长度.最小值和最大值)都适用于 ...
- python面向对象学习(五)多态
多态 多态:不同的 子类对象 调用相同的 父类方法,产生不同的执行结果 多态 可以 增加代码的灵活度 以 继承 和 重写父类方法 为前提 是调用方法的技巧,不会影响到类的内部设计 多态案例练习 需求 ...
- 【Spring】31、Spring的EL表达式
一.简介 Spring3中引入了Spring表达式语言—SpringEL,SpEL是一种强大,简洁的装配Bean的方式,他可以通过运行期间执行的表达式将值装配到我们的属性或构造函数当中,更可以调用JD ...
- Javascript继承5:如虎添翼----寄生式继承
/* * 寄生式继承 * 其实就是对原型继承的第二次封装,在封装过程中对继承的对象进行了扩展. * 也存在原型继承的缺点!! * 这种思想的作用也是为了寄生组合式继承模式的实现. */ //声明基对象 ...
- (一):C++分布式实时应用框架----整体介绍
C++分布式实时应用框架 (Cpp Distributed Real-time Application Framework) 版权声明:本文版权及所用技术归属smartguys团队所有,对于抄袭,非经 ...