C Linux带宽限制的应用程序

有什么方法可以尝试抑制循环内的send / sendto()函数。 我为我的networking创build了一个端口扫描器,我尝试了两种方法,但它们似乎只能在本地工作(当我在家用机器上testing它们时,它们工作,但是当我尝试在另一台不想创build的机器上testing它们时油门)。

方法1

我最初是parsing/proc/net/dev并在“bytes sent”属性中读取数据,并将我的睡眠时间设置为基于此。 这在当地工作(睡眠延迟调整,以调整带宽stream量),但只要我尝试在另一台服务器上也用/proc/net/dev它似乎没有调整数据的权利。 我在我本地扫描的一台机器上运行dstat ,并且输出的数据很快。

方法2

然后我试图跟踪总共发送了多less个字节,并将其添加到total_sentvariables中,我的带宽线程将读取并计算一个睡眠定时器。 这也适用于我的本地机器,但是当我在服务器上尝试时,它只是说每次我的带宽线程检查total_sent时只发送1-2个数据包,使我的带宽线程减less睡眠到0,但即使在0 total_sent由于睡眠时间减less,variables没有增加,而是保持不变。

总的来说,我想要一种方法来监视Linux计算机的带宽,并计算一个hibernate时间,我可以传递到每个send / sendto()套接字调用之前或之后的usleep()来抑制带宽。

编辑:我忘了提到的一些其他的事情是,我有一个speedtest函数,计算机器的上传速度,我有2个线程。 1线程根据带宽使用情况调整全局睡眠定时器,线程2将数据包发送到远程机器上的端口,以testing它们是否打开并对它们进行指纹(现在我只是使用带有sendto() udp数据包来testing这一切)。

如何使用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数据包进行testing。 sock是我的sockfdbuff是一个64字节的字符数组,填充了“A”, sinmy sockaddr_in

  while(1) { TOTAL_BYTES_SEND += 64; sendto(sock, buff, strlen(buff), 0, (struct sockaddr *) &sin, sizeof(sin)) usleep(SLEEP); } 

我知道我的套接字函数工作,因为我可以看到在我的本地机器和远程机器上的dstat的用法。 这个带宽代码在我的本地系统上工作(所有的variables都是按照它们应该改变的),但是在服务器上,我尝试testing已经过的字节不会改变(每次迭代的线程总是64/128),并导致SLEEP限制为0这在理论上应该使机器更快地发送数据包,但即使SLEEP等于0逝去的字节仍然是64/128。 我还在if语句中编写了sendto()函数,检查返回-1的函数,并通过printf提示错误代码,但是在testing中没有一个。

Solutions Collecting From Web of "C Linux带宽限制的应用程序"

看起来这可以通过计算发送线程中的油门睡眠时间来最直接地解决。 我不知道我看到另一个线程的好处来做这个工作。

这是一个方法来做到这一点:

选择一个您将在其中测量您的发送速率的时间窗口。 基于你的目标带宽,这将会给你在这段时间内的最大字节数。 然后可以检查每个sendto()后是否发送了多少字节。 如果你确实超过了字节阈值,那么睡眠直到窗口结束才能执行节流。

这是一些未经测试的代码,显示了这个想法。 对不起,clock_gettime和struct timespec增加了一些复杂性。 谷歌有一些很好的代码片段,用于进行更完整的比较,添加和结构timespec减法。

 #define MAX_BYTES_PER_SECOND (128L * 1024L) #define TIME_WINDOW_MS 50L #define MAX_BYTES_PER_WINDOW ((MAX_BYTES_PER_SECOND * TIME_WINDOW_MS) / 1000L) #include <time.h> #include <stdlib.h> int foo(void) { struct timespec window_start_time; size_t bytes_sent_in_window = 0; clock_gettime(CLOCK_REALTIME, &window_start_time); while (1) { size_t bytes_sent = sendto(sock, buff, strlen(buff), 0, (struct sockaddr *) &sin, sizeof(sin)); if (bytes_sent < 0) { // error handling } else { bytes_sent_in_window += bytes_sent; if (bytes_sent_in_window >= MAX_BYTES_PER_WINDOW) { struct timespec now; struct timespec thresh; // Calculate the end of the window thresh.tv_sec = window_start_time.tv_sec; thresh.tv_nsec = window_start_time.tv_nsec; thresh.tv_nsec += TIME_WINDOW_MS * 1000000; if (thresh.tv_nsec > 1000000000L) { thresh.tv_sec += 1; thresh.tv_nsec -= 1000000000L; } // get the current time clock_gettime(CLOCK_REALTIME, &now); // if we have not gotten to the end of the window yet if (now.tv_sec < thresh.tv_sec || (now.tv_sec == thresh.tv_sec && now.tv_nsec < thresh.tv_nsec)) { struct timespec remaining; // calculate the time remaining in the window // - See google for more complete timespec subtract algorithm remaining.tv_sec = thresh.tv_sec - now.tv_sec; if (thresh.tv_nsec >= now.tv_nsec) { remaining.tv_nsec = thresh.tv_nsec - now.tv_nsec; } else { remaining.tv_nsec = 1000000000L + thresh.tv_nsec - now.tv_nsec; remaining.tv_sec -= 1; } // Sleep to end of window nanosleep(&remaining, NULL); } // Reset counters and timestamp for next window bytes_sent_in_window = 0; clock_gettime(CLOCK_REALTIME, &window_start_time); } } } } 

如果您希望在应用程序级别执行此操作,则可以使用实用程序(如滴流)来限制或调整应用程序可用的套接字传输速率。

例如,

 trickle -s -d 50 -w 100 firefox 

将以50KB / s的最大下载速率和100KB的峰值检测窗口启动firefox 。 更改这些值可能会产生适合您的应用程序测试的内容。