Clumsy-Windows下网络环境模拟工具

Clumsy是一款基于C语言开发的开源网络模拟工具,可在Windows平台模拟不稳定网络状态,支持延迟、丢包等功能,适用于应用程序极端网络状态下的调试。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

下载页
http://jagt.github.io/clumsy/cn/download

项目的代码可以在github上获取,在下载页面有编译好的版本。强烈建议在使用前花点时间阅读一下文档,来 了解 clumsy 的功能和限制。

目前的实现中有一些难以绕过的限制和问题,列表如下:

回送的输入数据包(Loopback inbound packets)无法被重新注入。
仔细想想你就会发现我们没有很好的方法来区分一个回送数据包到底是被发出还是被接收到,因为它们的目标和来源 IP 地址都是本机。事实上 clumsy 底层的 WinDivert,以及其基于的 Windows Filtering Platform 把所有的回送数据包统统认为是输出 (Outbound) 数据包。这里需要记住的是,当你在本机上处理回送数据包的时候,你不能把 “inbound” 设置在 filter 条件中,最简单的方法就是在条件中简单的加上 “outbound”。另一件容易出问题的事情是,你本机的 IP 不仅仅只有 127.0.0.1 一个,还有类似路由器分配给你机器的 IP 也是属于你的本机 IP。
回送数据包会被处理两次。
因为所有的回送数据包都被认为是输出数据包,clumsy 会重复处理它们两次。一次是在发出的时候,一次是在接受到的时候。一个简单的例子是简单的把 filter 设置为 outbound,然后在 clumsy 中设置 500ms 的延迟并开启,之后在命令行里 ping localhost。这时你会发现延迟是 1000ms。当然你可以仔细的设置 filter 条件通过设置端口来只捕捉一部分的回送数据包,但是这样会比较麻烦。最简单的做法就是记住这个问题,然后设置参数的时候做相应的计算。
输入数据包的重新注入有些问题。
根据上面的描述,回送的输入包裹无法被重新注入。问题是现在有些来自包裹虽然其地址不是本机的 IP,其偶尔也会被认为是输入包裹。这种情况如果被捕捉到是无法进行重新注入的。这个问题仅仅影响非回送数据包,所以如果你仅仅是在本机上调试服务器和客户端那么是不会有这个问题的。未来版本的目标是准确的重现这个问题并进行修复。
无法根据进程来进行数据包过滤。
全系统级的数据包捕获虽然被列在了功能里,实际上是在当前的实现下,没法找到一个合适且稳定的方法来进行根据进程的数据包捕获。
如何使用

首先请根据你系统的版本(32位或64位)下载 clumsy 最新版本。注意如果你安装的是64位的系统那么一定要下载64位的 clumsy。另一件重要的事实 clumsy 需要管理员权限才能正常工作。双击打开 clumsy 的话会弹出 UAC 对话框。如果没有的话请右键点击 clumsy.exe 选择"以管理员身份运行"。如果一切正常,你应该能看到如下图的界面:
在这里插入图片描述

笔者最近因为需要在局域网内模拟一个实际情况(即存在丢包、延迟等情况)。网上搜了很多工具,大多基于linux。后来好不容易在网上搜索到一款2014年出现的网络模拟工具----Clumsy。

Clumsy是基于C语言开发的一款开源网络模拟工具。它能在Windows平台下人工造成不稳定的网络状态,应用它可以方便调试应用程序在极端网络状态下的表现。

Clumsy 首先根据用户选择的filter来拦截指定的网络数据。在 filter中可以设定你感兴趣的协议(tcp/udp),端口号,是接收还是发出的端口。你也可以通过简单的逻辑语句来进一步缩小范围。当 Clumsy 被激活时,只有符合这些标准的网络数据会被进行处理,而你不感兴趣的数据仍然会由系统正常传输。当被 filter 的网络数据包被拦截后,你可以选择 Clumsy 提供的功能来有目的性的调整网络情况,下面是Clumsy提供的功能介绍。

(1)延迟(Lag):把数据包缓存一段时间后再发出,这样能够模拟网络延迟的状况;

(2)丢包(Drop):随机丢弃一些数据;

(3)截流(Throttle):把一小段时间内的数据拦截下来后再在之后的同一时间一同发出去;

(4)重发(Duplicate):随机复制一些数据并与其本身一同发送;

(5)乱序(Out of order):打乱数据包发送的顺序;

(6)篡改(Tamper):随机修改小部分的包裹内容。

图1是Clumsy界面(此时丢包率为50%)。
在这里插入图片描述
图1:Clumsy 0.2 运行页面

在局域网(正常情况下,零丢包)环境下,通过ping测试,不同丢包率下的实际丢包率。结果如下:
在这里插入图片描述
因此从一定程度上证明了该工具的效果很好,延迟也有测试,效果明显。

ffplay -x 900 -y 720 -fflags nobuffer -max_delay 5 -i rtsp://xxxx

测试丢包10%
在这里插入图片描述

丢包50%
在这里插入图片描述

<think>嗯,用户想找HAL_TIM_PeriodElapsedCallback函数的定义位置和用法。首先,我需要回忆一下STM32的HAL库结构。这个回调函数应该和定时器中断相关,对吧?当定时器的周期到了,就会触发这个回调函数。 根据用户提供的引用资料,特别是引用[3],里面提到使用HAL_TIM_Base_Start_IT来启动定时器并开启中断,然后实现中断服务程序中的任务。所以HAL_TIM_PeriodElapsedCallback应该是在用户代码中定义的,用来处理周期性的中断事件。HAL库通常采用回调机制,用户需要自己实现这些回调函数,比如这个函数可能是在定时器更新事件时被调用。 接下来,关于定义的位置,HAL库中的弱定义应该在某个头文件或源文件中,比如stm32xx_hal_tim.h或者对应的.c文件中。用户需要在自己的代码中重新定义这个函数,覆盖弱符号。例如,在main.c或者专门的定时器处理文件中定义。 用法方面,用户需要在初始化定时器并启动中断后,编写这个回调函数的内容,比如翻转LED或者处理数据。同时要注意定时器实例的判断,如果有多个定时器的话,需要用htim的参数来选择正确的定时器。 可能用户遇到的问题是没有正确实现回调函数,或者没有启动中断。需要检查是否调用了正确的启动函数,比如HAL_TIM_Base_Start_IT而不是HAL_TIM_Base_Start,后者可能不会开启中断。 另外,用户可能需要知道如何查找HAL库中的弱定义,这通常是在HAL的源文件中,使用__weak关键字修饰。例如在stm32xx_hal_tim.c中会有这个函数的弱定义,用户在自己的代码中重新实现即可。 还需要提醒用户,中断服务函数的名字可能和CubeMX生成的有关,确保中断向量表正确,以及中断优先级设置合理。如果有多个定时器,回调函数中需要通过htim->Instance来判断是哪个定时器触发的,从而执行不同的操作。 总结一下,回答应该包括回调函数的定义位置在用户代码中,需要覆盖HAL的弱定义,用法是在定时器中断发生时执行用户代码,并注意定时器实例的判断。同时提供示例代码和常见问题解答,帮助用户正确使用。</think>### HAL_TIM_PeriodElapsedCallback 函数解析 #### 1. 函数定义位置 `HAL_TIM_PeriodElapsedCallback` 是STM32 HAL库中定时器更新事件(周期中断)的**弱定义回调函数**,其默认实现位于HAL库的定时器驱动文件中(例如:`stm32xx_hal_tim.c`),但用户需要在工程中**重新实现该函数**以覆盖默认的弱定义[^3]。 具体来说: - **弱定义位置**:`stm32xx_hal_tim.c`(例如`stm32h7xx_hal_tim.c`) - **用户实现位置**:用户代码中(如`main.c`或自定义的定时器处理文件) #### 2. 函数作用 当定时器的计数器溢出(或达到预设周期值)时,触发更新事件中断,此时`HAL_TIM_PeriodElapsedCallback` 会被调用,用于执行用户自定义的周期性任务,例如:LED闪烁、传感器数据采集等[^3]。 #### 3. 函数原型 ```c __weak void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { // 默认空实现(需用户覆盖) } ``` #### 4. 使用步骤 1. **定时器初始化** 配置定时器参数(预分频系数、计数周期等),例如: ```c TIM_HandleTypeDef htim3; htim3.Instance = TIM3; htim3.Init.Prescaler = 8399; // 84MHz/(8400) = 10kHz htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 9999; // 10kHz/10000 = 1Hz HAL_TIM_Base_Init(&htim3); ``` 2. **启动定时器中断** 使用 `HAL_TIM_Base_Start_IT` 启动定时器并开启中断[^3]: ```c HAL_TIM_Base_Start_IT(&htim3); ``` 3. **实现回调函数** 在用户代码中重新定义函数: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM3) // 判断触发源 { HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5); // 示例:翻转LED } } ``` #### 5. 注意事项 - 若使用多个定时器,需在回调函数中通过 `htim->Instance` 判断具体触发源[^3]。 - 必须调用 `HAL_TIM_Base_Start_IT`(而非 `HAL_TIM_Base_Start`)以启用中断功能。 - 确保中断服务函数 `TIMx_IRQHandler` 已正确关联到定时器(通常由CubeMX自动生成)。 --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值