我已经创建了一个监视接口的应用程序,并返回每秒读取的数据包,如果执行它运行正常约30秒,直到我打开一个YouTube页面让计数器运行得有点高。几秒钟后,应用程序冻结并且什么都不做。这种情况发生在不规则的时间间隔,所以我猜测它的计数,代码,它用C语言编写。
#include <stdio.h>
#include <pcap.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <time.h>
#include <pthread.h>
void callThreads(u_char *useless, const struct pcap_pkthdr* pkthdr, const u_char* packet);
void *packetcalc(void *threadid);
static struct timespec time1, time2;
static int t = 0, i = 0;
static long rc;
static pthread_t threads[1];
int main(int argc, char *argv[]){
pcap_t* descr;
char errbuf[PCAP_ERRBUF_SIZE];
descr = pcap_open_live("eth0", BUFSIZ, 1, -1, errbuf);
if(descr == NULL){
printf("Error: pcap_open_live()\n");
return 1;
}
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
pcap_loop(descr, 0, callThreads, NULL);
return 0;
}
void callThreads(u_char *useless, const struct pcap_pkthdr* pkthdr, const u_char* packet){
if(i >= 2147483647){
//In case i gets full from counting too many packets
i = 0;
time1.tv_sec = 0;
}
++i;
rc = pthread_create(&threads[t], NULL, packetcalc, (void *) t);
}
void *packetcalc(void *threadid){
static int j;
static int temp = 0;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &time1);
if(temp != time1.tv_sec){
j = (i / time1.tv_sec);
printf("Packets: %d/sec\t(%d)\t(%d)\n", j, i, (int)time1.tv_sec);
temp = time1.tv_sec;
}
pthread_exit(NULL);
}
编辑:我是否也可以在虚拟机中运行此代码,因为多线程只分配了1个CPU?
答案 0 :(得分:2)
您正在为每个数据包创建一个线程,这是一个可怕的想法。只需在您提供给pcap_loop(3)
的回调函数中打印您需要的任何计数器就足够了。
答案 1 :(得分:1)
您的代码存在一些问题。首先,使用默认线程属性创建线程,这意味着它们被创建为可连接线程,即您必须稍后调用pthread_join()
,否则线程控制结构将保持不变。因此,代码中存在内存泄漏。可能是您应该检查pthread_create
的返回值,以便检测何时发生错误,例如系统无法创建新线程,并且您的数据包计数例程已停止被调用。您还可以使用以下代码创建处于分离状态的新线程:
pthread_attr_t attr;
pthread_attribute_init(&attr);
pthread_attribute_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&threadid, &attr, packetcalc, (void *) t);
pthread_attribute_destroy(&attr);
以后不需要连接分离的线程。它们在线程退出时释放所有资源。
其次,线程使用一些全局变量,就好像它们是私有的,而实际上它们是共享的。这包括全局time1
以及本地j
和temp
,它们被声明为static
,因此在线程之间共享。
请注意,创建线程是一项昂贵的操作。当您的代码等待pthread_create
完成时,新数据包可能会到达并填满由libpcap
使用的循环缓冲区,因此您可能会丢失一些数据包。事实上,每个数据包使用一个线程是一个非常糟糕的主意。而是只使用两个线程 - 一个运行pcap
循环,另一个循环计数数据包并计算和打印数据包速率。