【发布时间】:2012-11-13 12:24:44
【问题描述】:
有哪些方法可以尝试在循环中限制 send/sendto() 函数。我正在为我的网络创建一个端口扫描仪,我尝试了两种方法,但它们似乎只能在本地工作(当我在我的家用机器上测试它们时它们工作,但是当我尝试在另一台机器上测试它们时它不想创建适当的节流阀)。
方法一
我最初是在解析 /proc/net/dev 并读取“发送的字节数”属性并以此为基础来确定我的睡眠时间。这在本地有效(睡眠延迟正在调整以调整带宽流量),但是当我在另一台服务器上尝试使用/proc/net/dev 时,它似乎并没有正确调整数据。我在本地扫描的机器上运行dstat,它正在快速输出大量数据。
方法2
然后我尝试跟踪我发送的总字节数并将其添加到total_sent 变量中,我的带宽线程将读取该变量并为其计算睡眠计时器。这也适用于我的本地机器,但是当我在服务器上尝试它时,它说每次我的带宽线程检查 total_sent 时它只发送 1-2 个数据包,使我的带宽线程将睡眠减少到 0,但即使是 0 total_sent 变量并没有因为睡眠时间减少而增加,而是保持不变。
总的来说,我想要一种方法来监控 Linux 计算机的带宽并计算我可以在每个 send/sendto() 套接字调用之前或之后传递到 usleep() 以限制带宽的睡眠时间。
编辑:我忘了提到的其他一些事情是我确实有一个 speedtest 函数来计算机器的上传速度,并且我有 2 个线程。 1个线程根据带宽使用情况调整全局睡眠定时器,线程2将数据包发送到远程机器上的端口以测试它们是否打开并对其进行指纹识别(现在我只是使用带有sendto()的udp数据包进行测试这一切)。
如何使用usleep() 为send/sendto() 调用实施带宽限制。
编辑:这是我的带宽监控线程的代码。不要担心结构的东西,这只是我将数据传递给线程的方式。
void *bandwidthmonitor_cmd(void *param)
{
int i = 0;
double prevbytes = 0, elapsedbytes = 0, byteusage = 0, maxthrottle = 0;
//recreating my param struct i passed to the thread
command_struct bandwidth = *((command_struct *)param);
free(param);
//set SLEEP (global variable) to a base time in case it was edited and not reset
SLEEP = 5000;
//find the maximum throttle speed in kb/s (takes the global var UPLOAD_SPEED
//which is in kb/s and times it by how much bandwidth % you want to use
//and devides by 100 to find the maximum in kb/s
//ex: UPLOAD_SPEED = 60, throttle = 90, maxthrottle = 54
maxthrottle = (UPLOAD_SPEED * bandwidth.throttle) / 100;
printf("max throttle: %.1f\n", maxthrottle);
while(1)
{
//find out how many bytes elapsed since last polling of the thread
elapsedbytes = TOTAL_BYTES_SEND - prevbytes;
printf("elapsedbytes: %.1f\n", elapsedbytes);
//set prevbytes to our current bytes so we can have results next loop
prevbytes = TOTAL_BYTES_SEND;
//convert our bytes to kb/s
byteusage = 8 * (elapsedbytes / 1024);
//throttle control to make it adjust sleep 20 times every 30~
//iterations of the loop
if(i & 0x40)
{
//adjust SLEEP by 1.1 gain
SLEEP += (maxthrottle - byteusage) * -1.1;//;
if(SLEEP < 0){
SLEEP = 0;
}
printf("sleep:%.1f\n\n", SLEEP);
}
//sleep the thread for a short bit then start the process over
usleep(25000);
//increment variable i for our iteration throttling
i++;
}
}
我的发送线程只是一个简单的sendto() 例程,在while(1) 循环中发送udp 数据包进行测试。 sock 是我的sockfd,buff 是一个用“A”填充的 64 字节字符数组,sin 是 my sockaddr_in。
while(1)
{
TOTAL_BYTES_SEND += 64;
sendto(sock, buff, strlen(buff), 0, (struct sockaddr *) &sin, sizeof(sin))
usleep(SLEEP);
}
我知道我的套接字函数可以工作,因为我可以在本地机器和远程机器上看到 dstat 中的用法。此带宽代码适用于我的本地系统(所有变量都应更改)但在服务器上我尝试对经过的字节进行测试并没有更改(每次线程迭代始终为 64/128)并导致SLEEP 节流到 0 理论上应该使机器更快地发送数据包,但即使 SLEEP 等于 0 elapsedbytes 仍然是 64/128。我还在 if 语句中编码了 sendto() 函数,检查函数是否返回 -1 并通过 printf-ing 错误代码提醒我,但我所做的测试中没有。
【问题讨论】:
-
“然后我尝试跟踪我发送的总字节数,并将其添加到我的带宽线程将读取并计算睡眠计时器的 total_sent 变量中。” — 这听起来对我来说是正确的,请发布您尝试执行此操作的代码。
-
@AlexeyFeldgendler:我提出了一些我的代码。这可能是互斥锁问题吗?我正在从 2 个线程快速读取和写入同一个变量,没有任何锁定。
-
作为测试,我将 sendto 行更改为
if((TOTAL_BYTES_SEND += sockto(sock,...)) == -1) { printf("error"); }并且没有错误,我现在得到 sendto() 函数的真实输出,但我拥有的服务器上传速度为 4000kb/s elapsedbytes 仍然非常低,这会导致 SLEEP 变为 0,这不会像在我的服务器上那样增加 elapsedbytes(睡眠会上下调节以维持计算为 maxthrottle 的 kb/s) -
您应该将经过的字节数除以自上次测量以来经过的时间。否则,您得到的是发送的一些随机字节数(在未指定的间隔内),这与 maxthrottle (以 kb/s 为单位)无法直接比较。此外,这段代码充满了竞争条件。您应该使用互斥锁来同步对共享变量的访问。
标签: c linux throttling