我有一个HTTP线程代理,即针对客户端的每个请求都生成一个线程:现在我想收集一些统计数据,例如每秒位数(bps)和每秒数据包(pps)。
我希望代码只做一件事,因此,如果线程处理连接,那么它也不会为每个数据包计算bps和pps,因此我将其留给另一个线程。
我为来自客户端的每个HTTP请求创建一个线程,如果代理成功连接到请求的远程服务器,则代理将实际的HTTP请求发送到服务器,并且在路由数据之前,连接线程会创建一个日志记录线程:日志记录线程将计算bps和直到连接打开为止。连接线程向日志线程提供有关要过滤哪些数据包的信息(本地IP地址,本地端口,远程IP地址,远程端口),因此每个日志线程将仅过滤来自父连接线程的数据包。
我在为每个数据包计算bps和pps时遇到问题。
这是我在日志记录线程中循环捕获数据包的伪代码:
// pcap variables
pcap_t *handle;
struct pcap_pkthdr *header;
const u_char *pkt_data;
// timevals used to calculate delay from last filtered packet
struct timeval oldTimevalUpload;
struct timeval oldTimevalDownload;
memset(&oldTimevalUpload, 0, sizeof(oldTimevalUpload));
memset(&oldTimevalDownload, 0, sizeof(oldTimevalDownload));
// stopLogging is a boolean flag declared in connection "parent" thread:
// it is set to false when connection thread has done sending and
// receiving data and connection is going to be closed
while (((res = pcap_next_ex(handle, &header, &pkt_data)) >= 0) && (!stopLogging)) {
// check res
if (packet is upload) {
struct timeval difference;
timeval_subtract(&difference, &(header->ts), &oldTimevalUpload);
long long delay = (difference.tv_sec * 1000000) + difference.tv_usec;
long long acceptedPackets = ((long long)(pkt_data)) * 1000000;
long long acceptedBits = ((long long)(pkt_data+8)) * 8 * 1000000;
long long pps = acceptedPackets / delay;
long long bps = acceptedBits / delay;
debugRed(host << ", UPLOAD DIVIDE ACCEPTED PKTS " << acceptedPackets <<
" AND ACCEPTED BITS " << acceptedBits << " PER DELAY " << delay <<
" IS PPS " << pps << " AND BPS " << bps);
oldTimevalUpload.tv_sec = header->ts.tv_sec;
oldTimevalUpload.tv_usec = header->ts.tv_usec;
} else if (packet is download) {
// basically the same as above
}
}
debug("Quit logging connection " << localIPaddr << ":" << localPort << " and "
<< remoteIPaddr << ":" << remotePort);
pcap_close(handle);
这是一个示例输出:
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 1479811349890053 IS PPS 0 AND BPS 0
www.netflix.com DOWNLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 1479811350032141 IS PPS 0 AND BPS 0
www.netflix.com DOWNLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 4344 IS PPS 22845174953 AND BPS 182761414364
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 146464 IS PPS 677568822 AND BPS 5420551015
www.netflix.com DOWNLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 2815 IS PPS 35253797513 AND BPS 282030402841
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 2808 IS PPS 35341680911 AND BPS 282733470085
www.netflix.com DOWNLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 1120 IS PPS 88606642857 AND BPS 708853200000
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 1134 IS PPS 87512733686 AND BPS 700101925925
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 39658 IS PPS 2502381360 AND BPS 20019052498
www.netflix.com DOWNLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 176317 IS PPS 562846690 AND BPS 4502773890
www.netflix.com UPLOAD, DIVIDE ACCEPTED PKTS 99239440000000 AND ACCEPTED BITS 793915584000000 PER DELAY 136687 IS PPS 726034224 AND BPS 5808274261
我从来不知道我的家庭网络可以承受500 MBps以上的速度,因此一定有问题。
This page显示了如何计算bps和pps,并解释了
chars
中8 acceptedBits
的移位,但是无论如何我还是要报告下来。在这里,您可以看到函数pcap_next_ex
的第二个和第三个参数:基本上,我做了他所说的一切!为什么我会变得如此大而奇怪的bps和pps?
在Ubuntu 14.04上工作;不知道如何检查
libpcap
版本,但是locate libpcap
提供了以下信息:/home/dexter/Desktop/wireshark-1.99.9/wiretap/libpcap.c
/home/dexter/Desktop/wireshark-1.99.9/wiretap/libpcap.h
/usr/lib/x86_64-linux-gnu/libpcap.a
/usr/lib/x86_64-linux-gnu/libpcap.so
/usr/lib/x86_64-linux-gnu/libpcap.so.0.8
/usr/lib/x86_64-linux-gnu/libpcap.so.1.5.3
/usr/share/doc/libpcap-dev
/usr/share/doc/libpcap0.8
/usr/share/doc/libpcap0.8-dev
/usr/share/doc/libpcap-dev/changelog.Debian.gz
/usr/share/doc/libpcap-dev/copyright
/usr/share/doc/libpcap0.8/CREDITS.gz
/usr/share/doc/libpcap0.8/README.Debian
/usr/share/doc/libpcap0.8/README.gz
/usr/share/doc/libpcap0.8/changelog.Debian.gz
/usr/share/doc/libpcap0.8/copyright
/usr/share/doc/libpcap0.8-dev/changelog.Debian.gz
/usr/share/doc/libpcap0.8-dev/copyright
/var/lib/dpkg/info/libpcap-dev.[list,md5sums]
/var/lib/dpkg/info/libpcap0.8-dev.[list,md5sums,preinst]
/var/lib/dpkg/info/libpcap0.8:amd64.[list,md5sums,postinst,postrm,shlibs,symbols]
最佳答案
在您的代码中:
long long acceptedPackets = ((long long)(pkt_data)) * 1000000;
long long acceptedBits = ((long long)(pkt_data+8)) * 8 * 1000000;
而pkt_data是指针。
您要做的基本上是获取数据包数据的地址,将其转换为
long long
,加8(对于第二行),再乘以一个常数并将其视为您的值,这在语义上是不正确的。考虑到您的数据类型,您应该取消引用该指针(将pkt_data
转换为指向long long
的指针)。在代码中:
long long acceptedPackets = (*(long long*)(pkt_data)) * 1000000;
long long acceptedBits = (*(long long*)(pkt_data+8)) * 8 * 1000000;
// this also works:
//long long acceptedPackets = *(long long*)pkt_data * 1000000;
//long long acceptedBits = *((long long*)pkt_data + 1) * 8 * 1000000;
有关示例,请参见http://ideone.com/JqmRre
编辑:
从this guide:
这意味着
pkt_data
是数据包内容本身。除非数据包的前16个字节包含所需的信息(这是不正确的,因为它包含原始数据包,所以它具有ETH,IP和TCP / UDP header ),否则无法使用该数据。为了获取PPS指标,您必须在循环中实现一个简单的计数器(由于您正在每帧打印该指标,因此,一个简单的long long pps = (long long)(1.0 / delay);
就足够了-请注意,该除法以浮点数为准。 ,则应使用帧头信息。因此long long bps = (long long)(header->caplen * 8.0 / delay);
应该可以。附带说明一下,对于时间指标,由于您使用的是C++ 11,请尝试使用
chrono
。比timeval更清晰,更安全:添加一个
#include <chrono>
。您的最终代码应如下所示:
// pcap variables
pcap_t *handle;
struct pcap_pkthdr *header;
const u_char *pkt_data;
// Use of high_resolution_clock
std::chrono::high_resolution_clock::time_point oldTimeUpload = std::chrono::high_resolution_clock::now();
std::chrono::high_resolution_clock::time_point oldTimeDownload = std::chrono::high_resolution_clock::now();
// stopLogging is a boolean flag declared in connection "parent" thread:
// it is set to false when connection thread has done sending and
// receiving data and connection is going to be closed
while (((res = pcap_next_ex(handle, &header, &pkt_data)) >= 0) && (!stopLogging)) {
// check res
if (packet is upload) {
std::chrono::high_resolution_clock::time_point now = std::chrono::high_resolution_clock::now();
long long delay = std::chrono::duration_cast<std::chrono::nanoseconds>(now - oldTimeUpload).count();
long long pps = (long long)(1000000000.0 / delay);
long long bps = (long long)(header->caplen * 8 * 1000000000.0 / delay);
debugRed(host << ", UPLOAD DIVIDE PER DELAY " << delay <<
" IS PPS " << pps << " AND BPS " << bps);
oldTimevalUpload.tv_sec = header->ts.tv_sec;
oldTimevalUpload.tv_usec = header->ts.tv_usec;
} else if (packet is download) {
// basically the same as above
}
}
debug("Quit logging connection " << localIPaddr << ":" << localPort << " and "
<< remoteIPaddr << ":" << remotePort);
pcap_close(handle);
关于c++ - 使用libpcap收集连接统计信息,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40740939/