IPerf——网络测试工具介绍与源码解析(2)

简介: 对于IPerf源码解析,我是基于2.0.5版本在Windows下执行的情况进行分析的,提倡开始先通过对源码的简单修改使其能够在本地编译器运行起来,这样可以打印输出一些中间信息,对于理解源码的逻辑,程序实现的过程能够起到事半功倍的效果。

对于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模式下也不难理解。

相关文章
|
4天前
|
SQL 存储 关系型数据库
数据库开发之图形化工具以及表操作的详细解析
数据库开发之图形化工具以及表操作的详细解析
21 0
|
14天前
|
SQL 分布式计算 监控
Sqoop数据迁移工具使用与优化技巧:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入解析Sqoop的使用、优化及面试策略。内容涵盖Sqoop基础,包括安装配置、命令行操作、与Hadoop生态集成和连接器配置。讨论数据迁移优化技巧,如数据切分、压缩编码、转换过滤及性能监控。此外,还涉及面试中对Sqoop与其他ETL工具的对比、实际项目挑战及未来发展趋势的讨论。通过代码示例展示了从MySQL到HDFS的数据迁移。本文旨在帮助读者在面试中展现Sqoop技术实力。
27 2
|
27天前
|
数据可视化 搜索推荐 BI
深度解析好用项目管理工具的功能优势
在选择项目管理工具时,重点在于全面的功能和高性价比。好工具应具备资源利用图(避免过度分配或闲置资源),团队协作功能(促进沟通与进度追踪),质量管理(如问题跟踪和自定义工作流),项目规划和跟踪(甘特图支持),任务管理(任务分解和依赖关系),以及费用跟踪。Zoho Projects、Microsoft Project、Jira等工具各有价格差异,例如,对于50个用户,Microsoft Project最贵,Zoho Projects最实惠,性价比高,适合中小企业。
30 2
|
1月前
|
JSON 数据格式
第三方系统或者工具通过 HTTP 请求发送给 ABAP 系统的数据,应该如何解析试读版
第三方系统或者工具通过 HTTP 请求发送给 ABAP 系统的数据,应该如何解析试读版
27 0
|
3月前
|
SQL Java 数据库
深入解析MyBatis-Plus中静态工具Db的多种用法及示例
深入解析MyBatis-Plus中静态工具Db的多种用法及示例
120 0
|
3月前
|
网络协议 安全
DNS查询工具 - dig
【1月更文挑战第4天】
89 0
|
4月前
|
NoSQL 关系型数据库 MySQL
分布式锁的原理解析与实现工具介绍
分布式锁的原理解析与实现工具介绍
37 1
|
5月前
|
JavaScript IDE 前端开发
TypeScript 提供了丰富的工具和框架来提高开发效率。具体应用案例解析
TypeScript 提供了丰富的工具和框架来提高开发效率。具体应用案例解析
|
3月前
|
网络协议
DNS查询工具 - nslookup
【1月更文挑战第5天】
142 1
|
2月前
|
设计模式 测试技术 Go
Go 项目必备:Wire 依赖注入工具的深度解析与实战应用
在现代软件开发中,依赖注入(Dependency Injection,简称 DI)已经成为一种广泛采用的设计模式。它的核心思想是通过外部定义的方式,将组件之间的依赖关系解耦,从而提高代码的可维护性、可扩展性和可测试性。然而,随着项目规模的增长,手动管理复杂的依赖关系变得日益困难。这时,依赖注入代码生成工具就显得尤为重要。在众多工具中,Wire 以其简洁、强大和易用性脱颖而出,成为 Go 语言项目中的宠儿。本文将带你深入了解 Wire 的安装、基本使用、核心概念以及高级用法,并通过一个实际的 web 博客项目示例,展示如何利用 Wire 简化依赖注入的实现。准备好了吗?让我们开始这场代码解耦的奇

推荐镜像

更多