2012-07-24 29 views
6

Mam program, który wysyła zestaw pakietów TCP SYN do hosta (przy użyciu nieprzetworzonych gniazd) i używa libpcap (z filtrem) w celu uzyskania odpowiedzi. Próbuję zaimplementować to w asynchronicznej strukturze we/wy, ale wydaje się, że brakuje niektórych odpowiedzi (mianowicie pierwszych pakietów z serii, gdy zajmuje ona mniej niż 100 microseconds między TCP SYN a odpowiedzią). Uchwyt pcap jest ustawiony tak:Asynchroniczna libpcap: utrata pakietów?

pcap_t* pcap = pcap_open_live(NULL, -1, false, -1, errorBuffer); 
pcap_setnonblock(pcap, true, errorBuffer); 

Następnie dodaję filtr (zawartej na strunie filterExpression):

struct bpf_program filter; 
pcap_compile(pcap, &filter, filterExpression.c_str(), false, 0); 
pcap_setfilter(pcap, &filter); 
pcap_freecode(&filter); 

A na pętli, po wysłaniu każdego pakietu, używam wybierz wiedzieć jeśli mogę odczytać z libpcap:

int pcapFd = pcap_get_selectable_fd(pcap); 
fd_set fdRead; 
FD_ZERO(&fdRead); 
FD_SET(pcapFd, &fdRead); 
select(pcapFd + 1, &fdRead, NULL, NULL, &selectTimeout); 

i przeczytać:

if (FD_ISSET(pcapFd, &fdRead)) { 
    struct pcap_pkthdr* pktHeader; 
    const u_char* pktData; 
    if (pcap_next_ex(pcap, &pktHeader, &pktData) > 0) { 
     // Process received response. 
    } 
    else { 
     // Nothing to receive (or error). 
    } 
} 

Jak już wcześniej wspomniałem, niektóre pakiety są pomijane (wchodząc w "nic do odbioru"). Wiem, że te pakiety istnieją, ponieważ mogę je przechwytywać synchronicznie (używając tcpdump lub wątku z uruchomioną pcap_loop). Czy brakuje tu jakiegoś szczegółu? Czy to jest problem z libpcap?

+0

Może się zdarzyć, że wysyłasz zbyt wiele żądań zbyt szybko, a serwer wysyła odpowiedzi szybciej, niż można sobie z nimi poradzić, co powoduje przeciążenie bufora sieciowego systemu operacyjnego i upuszczenie pakietów. Możliwe też, że gniazdo odbiornika nie zostanie skonfigurowane na czas, aby obsłużyć początkowe odpowiedzi. Czy możesz zweryfikować, że wszystkie odpowiedzi, które przyjmujesz, faktycznie się tam dostają? Todo to uruchom tcpdump na tym samym interfejsie co aplikacja jednocześnie.Jeśli zobaczysz wszystkie pakiety, których oczekujesz w tcpdump, a nie w twojej aplikacji, możesz mieć jeden z powyższych problemów. – ryanbwork

+0

Już to zrobiłem (tcpdump na boku, ale także pcap_loop inny wątek) i wszystkie pakiety tam były. Dlatego nie sądzę, żebym wysyłał odpowiedzi zbyt szybko. Jak mogę sprawdzić, czy moje gniazdo odbiornika (tj. Libpcap) nie jest jeszcze skonfigurowane? Miałoby to sens, ponieważ utracone odpowiedzi są zawsze pierwszym lub dwoma. –

+0

Nawet jeśli zobaczysz pakiety w tcpdump, mogą one zostać usunięte przez system operacyjny, jeśli twoja aplikacja nie będzie w stanie obsłużyć stawki, z jaką są odbierane. Jeśli twoja aplikacja zaczyna się po wysłaniu odpowiedzi, spróbuj dodać znaczne opóźnienie przed wysłaniem początkowej odpowiedzi z serwera; jeśli pomyślnie otrzymasz wszystkie odpowiedzi, znajdziesz swój problem. – ryanbwork

Odpowiedz

1

To wydaje się być problemem z libpcap przy użyciu mapowania pamięci pod Linuksem. Szczegółowe informacje znajdują się pod adresem my other question.

+0

więc, rozwiązałeś ten problem? jak włączyć mapowanie pamięci dla libpcap? – misteryes

1

Jeśli FD dla pcap_t jest zgłaszane jako czytelny select() (lub poll() lub cokolwiek wezwanie/mechanizm używasz), nie ma gwarancji, że oznacza to, że tylko jeden pakiet można odczytać bez blokowania.

Jeśli używasz pcap_next_ex(), będziesz czytać tylko jeden pakiet; Jeśli istnieje więcej niż jeden pakiet do odczytania, to jeśli wykonasz kolejny numer select(), powinien on natychmiast powrócić, zgłaszając FD jako możliwy do odczytania, w takim przypadku prawdopodobnie prawdopodobnie ponownie zadzwonisz pod numer pcap_next_ex() i tak dalej. Oznacza to co najmniej jedno wywołanie systemowe na pakiet (select()) i prawdopodobnie więcej połączeń, w zależności od wersji systemu operacyjnego i wersji posiadanej biblioteki libpcap.

Jeśli zamiast tego miałbyś wywołać pcap_dispatch(), z argumentem liczby pakietów równym -1, to wywołanie zwróci wszystkie pakiety, które można uzyskać za pomocą pojedynczej operacji odczytu i przetworzy je wszystkie, więc na większości platformy, możesz otrzymać wiele pakietów z jednym lub dwoma wywołaniami systemowymi, jeśli dostępnych jest wiele pakietów (co przy dużym ruchu w sieci, jak możesz uzyskać, jeśli testujesz swój program z powodzią SYN, prawdopodobnie tak się stanie) .

Ponadto w systemach Linux obsługujących przechwytywanie mapowania pamięci (jak sądzę, wszystkie jądra 2.6 i nowsze, i większość, jeśli nie wszystkie, jądra 2.4), oraz nowsze wersje libpcap, pcap_next_ex() musi wykonać kopię pakietu, aby uniknąć zmiany pakietu przez jądro pod kodem przetwarzającym pakiet i aby uniknąć "zamknięcia" gniazda w buforze pierścienia na czas nieokreślony, więc istnieje dodatkowa kopia.

+0

+1 Powszechna pułapka dla użytkowników nieobeznanych z asynchronicznymi I/O :) Powinieneś czytać!))) –

+0

Chociaż jest to przydatna informacja, tak nie jest w tym przypadku. Głównym problemem jest "wybierz" oskarżając aktywne 'pcap_t', a następnie' pcap_next_ex' zwracające zero. Zauważ, że "utracone pakiety" wpadają w "nic do odbioru". –