C Linux Bandwidth Throttling of Application

后端 未结 2 592
醉酒成梦
醉酒成梦 2021-01-14 15:01

What are some ways I can try to throttle back a send/sendto() function inside a loop. I am creating a port scanner for my network and I tried two m

相关标签:
2条回答
  • 2021-01-14 15:22

    It seems like this could be most directly solved by calculating the throttle sleep time in the send thread. I'm not sure I see the benefit of another thread to do this work.

    Here is one way to do this:

    Select a time window in which you will measure your send rate. Based on your target bandwidth this will give you a byte maximum for that amount of time. You can then check to see if you have sent that many bytes after each sendto(). If you do exceed the byte threshold then sleep until the end of the window in order to perform the throttling.

    Here is some untested code showing the idea. Sorry that clock_gettime and struct timespec add some complexity. Google has some nice code snippets for doing more complete comparisons, addition, and subtraction with struct 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);
          }
        }
      }
    }
    
    0 讨论(0)
  • 2021-01-14 15:29

    If you'd like to do this at the application level, you could use a utility such as trickle to limit or shape the socket transfer rates available to the application.

    For instance,

    trickle -s -d 50 -w 100 firefox
    

    would start firefox with a max download rate of 50KB/s and a peak detection window of 100KB. Changing these values may produce something suitable for your application testing.

    0 讨论(0)
提交回复
热议问题