好的,所以我的系统可以连接到目标计算机上的任意数量的以太网端口。我的目标是遍历每个设备,收集大约20个数据包,或者如果它没有数据然后跳过它,直到我找到我正在寻找的数据,并选择该设备作为我的“捕获设备”。看起来很简单。但是,我很快就知道如果没有数据进入,libpcap不会简单地超时。因此,我尝试使用pcap_setnonblock将捕获设备设置为非阻塞模式。但是,这会导致我读到的目标端口完全被淘汰。这是我的代码。接受有关可能发生的事情的建议,或者甚至是更好的方法。感谢
PS。不要敲打Type1 Type2变量名,它们用于混淆。
pcap_if_t *alldevs;
pcap_if_t *d;
pcap_t *fp;
struct pcap_pkthdr *header;
const u_char *pkt_data;
char errbuf[PCAP_ERRBUF_SIZE];
const int FIND_DEVICE_PACKET_LIMIT = 20;
#ifdef WIN32
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
#else
if (pcap_findalldevs(&alldevs, errbuf) == -1)
#endif
{
cerr << "Error in pcap_findalldevs_ex: " << errbuf << endl;
return;
}
// For each device, capture until timeout
// or until a matching packet is found.
for(d=alldevs; d; d=d->next)
{
if ((fp = pcap_open_live(d->name,
1514 /*snaplen*/,
1 /*flags, 1=promiscuous, 0=not promiscuous*/,
20 /*read timeout*/,
errbuf)
) == NULL)
{
cerr << endl << "Unable to open the adapter." << endl;
continue;
}
int res = 0;
int packetCounter = 0;
pcap_setnonblock(fp, true, errbuf);
// Capture at most FIND_DEVICE_PACKET_LIMIT packets
// to determine whether scanner is sending packets
// or no scanner found.
while ((res = pcap_next_ex(fp, &header, &pkt_data)) >=0) {
struct iphdr *iph = (struct iphdr *)(pkt_data + sizeof(struct ethhdr));
struct udphdr *udph = (struct udphdr*)(pkt_data + (iph->ihl*4) + sizeof(struct ethhdr));
u_int destPort = ntohs(udph->dest);
if (destPort==TYPE1_DATA_PORT || destPort==TYPE1_GPS_PORT) {
detectedScanners->type1 = true;
} else if (destPort==TYPE2_DATA_PORT || destPort==TYPE2_STATUS_PORT || destPort==TYPE2_NMEA_PORT) {
detectedScanners->type2 = true;
}
if (++packetCounter > FIND_DEVICE_PACKET_LIMIT) {
break;
}
}
if (detectedScanners->type1==true || detectedScanners->type2==true) {
*interface = d->name;
break;
}
}
答案 0 :(得分:1)
在非阻塞模式下,如果没有可读的数据包,pcap_next_ex()
将返回0,并且 NOT 将返回任何数据包信息,因此,如果它返回0,则应该不查看header
或packet_data
指向的任何内容。
即,
while ((res = pcap_next_ex(fp, &header, &pkt_data)) >=0) {
if (res != 0) {
struct iphdr *iph = (struct iphdr *)(pkt_data + sizeof(struct ethhdr));
struct udphdr *udph = (struct udphdr*)(pkt_data + (iph->ihl*4) + sizeof(struct ethhdr));
u_int destPort = ntohs(udph->dest);
if (destPort==TYPE1_DATA_PORT || destPort==TYPE1_GPS_PORT) {
detectedScanners->type1 = true;
} else if (destPort==TYPE2_DATA_PORT || destPort==TYPE2_STATUS_PORT || destPort==TYPE2_NMEA_PORT) {
detectedScanners->type2 = true;
}
if (++packetCounter > FIND_DEVICE_PACKET_LIMIT) {
break;
}
}
}
但请注意,您的程序将在该循环中持续旋转,消耗CPU,永远。这意味着您永远不会看过第一个设备。
您可能真正想做的是:
pcap_t *
放入数组中,并将其置于非阻塞模式; pcap_get_selectable_fd()
,在Windows上调用pcap_getevent()
,并将该调用的结果保存到数组中(可以使用并行数组或结构数组)使用pcap_t *
和int
或HANDLE
作为成员); select()
或poll()
上int
的所有pcap_get_selectable_fd()
上使用WaitForMultipleObjects()
或HANDLE
{ {1}}来自Windows上的pcap_getevent()
,当select()
/ poll()
/ WaitForMultipleObjects()
返回时,请尝试从的每个中读取数据包pcap_t *
使用pcap_next_ex()
,并在收到数据包时对其进行处理。这样,您可以并行扫描所有设备,并且不会旋转CPU。