2011-11-17 65 views
4

我有一個網絡應用程序,它使用 ActiveResource與另一臺服務器進行通信,該服務器對 連接有一個速率限制。我很好奇我怎樣才能最好地監測從我的網絡應用程序運行的主機 - 也就是說,從我的服務器上的Linux上的bash提示符,我如何測量我的機器每秒鐘發出的出站請求?每秒測量出站請求數?

我正在尋找給定接口,主機名, 和/或其某種組合的linux單線程,告訴我連接速率爲 對該服務器的連接速率。我已經接近tc和iftop這樣的工具,但那些報告的是傳輸的數據量,而不是所做的連接......所以它不是我想要的。我很樂意看到的東西像 :


$ awesometool --host thetargethost.com --interface eth0的--interval 5個

收集統計...每秒報告

請求thetargethost .COM通過接口eth0的

平均:23請求/秒分鐘:12請求/秒最大39請求/秒採取

5個樣品


任何人都可以指給我一個嗎?

回答

3

tcpdump(8)可以提供非常相似的東西;搜索與SYN標誌設置的TCP數據包趕上發往您的其他同行three-way handshake第一包:

$ sudo tcpdump -c 10 -i eth0 "tcp[tcpflags] & (tcp-syn) != 0 and dst 192.168.0.1" 
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode 
listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes 
18:26:24.800308 IP haig.59419 > 192.168.0.1.telnet: Flags [S], seq 3197302320, win 14600, options [mss 1460,sackOK,TS val 19460844 ecr 0,nop,wscale 7], length 0 
... 
18:26:27.420132 IP haig.59428 > 192.168.0.1.telnet: Flags [S], seq 1238498237, win 14600, options [mss 1460,sackOK,TS val 19461106 ecr 0,nop,wscale 7], length 0 
10 packets captured 
10 packets received by filter 
0 packets dropped by kernel 

你可以使用/usr/bin/time或shell的time內置,或者做一些算術與輸出中的時間戳,以獲得每秒的平均速率。 (用十幾包 - 這只是爲了演示。)

更新

我寫了一個小程序運行tcpdump(8),算上包,以及有多少包被的時間間隔內發送報告規定:

# ./counter --host 192.168.0.1 --interface eth0 --interval 3 
2 requests in 3 seconds; average 0.67 req/seq 
20 requests in 3 seconds; average 6.67 req/seq 
19 requests in 3 seconds; average 6.33 req/seq 
19 requests in 3 seconds; average 6.33 req/seq 
^C 
# ./counter --host 192.168.0.1 --interface eth0 --interval 5 
30 requests in 5 seconds; average 6.00 req/seq 
20 requests in 5 seconds; average 4.00 req/seq 
1176 requests in 5 seconds; average 235.20 req/seq 
1414 requests in 5 seconds; average 282.80 req/seq 
0 requests in 5 seconds; average 0.00 req/seq 
^C 

因爲它要求tcpdump(8)使用行緩衝輸出,我有點擔心,它可能無法擴展每秒超過200-300的請求,至少在我的硬件。但是如果沒有行緩衝輸出,在發送任何輸出之前,tcpdump(8)將等待其輸出緩衝區(詳見setvbuf(3))完整,導致極度緊張的結果。

但是如果你的連接率不是那麼高,這可能會做你所需要的。如果你的連接率更高,那麼這個小小的黑客可能是最好的忽略 - 它讓我感到可能是計數流。

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <getopt.h> 
#include <signal.h> 
#include <errno.h> 
#include <fcntl.h> 
#include <sys/types.h> 

#define CMDLEN 1024 
#define TCPDUMPLEN 4096 

int show_stats; 
long counter; 

void alarm_handler(int signum) 
{ 
    show_stats = 1; 
} 

void install_handler(void) 
{ 
    struct sigaction sa; 

    memset(&sa, 0, sizeof(sa)); 

    sigemptyset(&sa.sa_mask); 
    sa.sa_handler = &alarm_handler; 
    if (sigaction(SIGALRM, &sa, NULL) == -1) { 
     perror("Can't install alarm handler"); 
     exit(1); 
    } 
} 

int count_lines(char *p, int bytes) 
{ 
    int counter = 0; 
    char *i; 
    for (i=p; i < p+bytes ; i++) { 
     if (*i == '\n') 
      counter++; 
    } 
    return counter; 
} 

int spawn_tcpdump(char *host, char *interface) 
{ 
    int fd[2]; 
    pid_t child; 

    if (pipe(fd) == -1) { 
     perror("Can't create pipes"); 
     exit(1); 
    } 

    child = fork(); 

    if (child == -1) { 
     perror("Can't fork(2) for tcpdump"); 
     exit(1); 
    } 

    if (child == 0) { 
     int null; 
     int len; 
     char syn_and_dst[CMDLEN]; 

     len = snprintf(syn_and_dst, CMDLEN, "tcp[tcpflags] & (tcp-syn) != 0 and dst %s", host); 

     if (len > CMDLEN) { 
      perror("host argument too long"); 
      exit(1); 
     } 

     /* child writes into pipe */ 
     close(fd[0]); 
     dup2(fd[1], STDOUT_FILENO); 

     /* throw away first two lines of tcpdump output */ 
     null = open("/dev/null", O_WRONLY); 

     if (null == -1) { 
      perror("Can't open /dev/null"); 
      exit(1); 
     } 

     dup2(null, STDERR_FILENO); 

     execl("/usr/sbin/tcpdump", "tcpdump", "-l", "-n", "-s 96", "-i", interface, syn_and_dst, (char *) NULL); 
     /* can't reach */ 
     perror("Cannot execute tcpdump"); 
     exit(1); 
    } else { 
     /* parent reads from pipe */ 
     close(fd[1]); 
     return fd[0]; 
    } 
} 

int main(int argc, char *argv[]) 
{ 
    int tcpdump; 
    char *host; 
    char *interface; 
    long interval; 


    while (1) { 
     int option_index; 
     int c; 

     static struct option opts[] = { 
      {"host", required_argument, NULL, 'h'}, 
      {"interface", required_argument, NULL, 'i'}, 
      {"interval", required_argument, NULL, 'n'}, 
      {0, 0, 0, 0}, 
     }; 

     c = getopt_long(argc, argv, "", opts, &option_index); 

     if (c == -1) 
      break; 

     switch (c) { 
      case 'h': 
       host = strdup(optarg); 
       break; 
      case 'i': 
       interface = strdup(optarg); 
       break; 
      case 'n': { 
        char *endptr; 
        interval = strtol(optarg, &endptr, 10); 
        if (!(optarg[0] != '\0' && endptr[0] == '\0')) { 
         fprintf(stderr, "Expected integer; invalid" 
           " input '%s'\n", optarg); 
         exit(1); 
        } 
       } 
       break; 
      default: 
       fprintf(stderr, "Option parsing error\n"); 
       exit(1); 
     } 

    } 

    if (optind < argc) { 
     fprintf(stderr, "unexpected arguments: "); 
     while (optind < argc) { 
      fprintf(stderr, "%s ", argv[optind++]); 
     } 
     fprintf(stderr, "\n"); 
    } 

    tcpdump = spawn_tcpdump(host, interface); 

    install_handler(); 
    alarm(interval); 

    while(1) { 
     if (show_stats) { 
      printf("%ld requests in %ld seconds; average %2.2f req/seq\n", 
        counter, interval, (double)counter/(double)interval); 
      counter = 0; 
      show_stats = 0; 
      alarm(interval); 
     } else { 
      char buffer[TCPDUMPLEN]; 
      int ret; 

      memset(buffer, 0, TCPDUMPLEN); 
      ret = read(tcpdump, buffer, TCPDUMPLEN); 
      if (ret == -1 && errno == EINTR) { 
       /* nop */ 
      } else if (ret == -1) { 
       perror("read"); 
       exit(1); 
      } else { 
       counter += count_lines(buffer, ret); 
      } 
     } 
    } 

    exit(0); 
} 
+0

這是一個很好的開始,但對於-c的任何值都會在不會發生連接的情況下出現問題。我需要它能夠每秒鐘報告'0'連接,這可能會在下班時間發生,但這會在此期間掛起(等待)。有沒有辦法將tcpdump轉儲到tmp文件幾秒鐘,然後grep來計數?例如,在Munin使用這種解決方案時,我想每5分鐘獲取一次快照,並在5秒或更短的時間內獲取。 –

+0

優秀! (我原來的評論是在更新之前)。我用perl攻擊了一些東西,定義了shell函數和字數,但是你的解決方案要好得多。感謝那。 –