2015-04-14 7 views
6

Niejawne pytanie brzmi: jeśli Linux blokuje wywołanie send(), gdy bufor wysyłania gniazda jest pełny, dlaczego mają być jakieś utracone pakiety?W systemie Linux, dlaczego tracę pakiety UDP, jeśli wywołuję send() tak szybko, jak to możliwe?

Więcej szczegółów: Napisałem małe narzędzie w C, aby wysłać pakiety UDP tak szybko jak to możliwe do adresu i portu emisji pojedynczej. Wysyłam ładunek UDP 1450 bajtów za każdym razem, a pierwsze bajty są licznikiem, który zwiększa się o 1 dla każdego pakietu. Uruchamiam go na Fedorze 20 wewnątrz VirtualBox na komputerze stacjonarnym z nickiem 1Gb (= dość powolnym).

Potem napisałem małe narzędzie do odczytywania pakietów UDP z danego portu, które sprawdzają licznik pakietu względem jego własnego licznika i wypisują komunikat, jeśli są różne (to znaczy, że utracono 1 lub więcej pakietów). Uruchomiłem go na serwerze bi-xeon Fedory 20 z 1Gb ethernet nic (= super szybki). Pokazuje wiele utraconych pakietów.

Obie maszyny są w sieci lokalnej. Nie wiem dokładnie ile przeskoków między nimi, ale nie sądzę, że istnieje między nimi więcej niż 2 routery.

Czego próbowałem:

  • Dodaj opóźnienia po każdej send(). Jeśli ustawię opóźnienie na 1ms, to żadne pakiety nie zostaną utracone. Opóźnienie 100us zacznie tracić pakiety.
  • Zwiększ rozmiar bufora gniazda odbiorczego do 4 MB za pomocą setsockopt(). To nie ma znaczenia ...

Proszę mnie oświecić!

+0

Nie sądzę, że to naprawdę jest pytanie programistyczne. Jest jednak trochę mętny. – unwind

Odpowiedz

6

Dla UDP opcja gniazda SO_SNDBUF ogranicza tylko rozmiar datagramu, który można wysłać. Nie ma jawnie ograniczającego bufora gniazda wysyłkowego, tak jak w przypadku TCP. Oczywiście istnieje kolejkowanie klatek w jądrze do karty sieciowej.

Innymi słowy, send(2) może upuścić datagram bez zwrócenia błędu (sprawdź opis ENOBUFS na dole strony podręcznika).

Następnie pakiet może być spadła prawie wszędzie na ścieżce:

  • wysyłania karta sieciowa nie ma wolnych zasobów sprzętowych do obsługi żądania, ramka jest odrzucana,
  • pośrednie urządzenie routingu nie ma dostępny przestrzeń buforowa lub implementuje algorytm unikania przeciążenia, odrzuca pakiet, odbierająca karta sieciowa nie może akceptować ramek ethernetowych w zadanym tempie, niektóre ramki są po prostu ignorowane.
  • Aplikacja czytnika nie ma wystarczającej ilości miejsca do odbiórki gniazda, aby dostosować się do skoków natężenia ruchu, datagramy z kropli kernela.

Z tego, co powiedzieliśmy, wydaje się bardzo prawdopodobne, że maszyna wirtualna nie jest w stanie wysłać pakietów z wysoką szybkością. Powąchaj przewód za pomocą tcpdump(1) lub wireshark(1) tak blisko źródła, jak to możliwe, i sprawdź numery sekwencji - to by powiedzieć, czy to winien jest nadawcę.

+1

Dzięki Nikolai. Strona man rzeczywiście stwierdza "Pakiety są po cichu upuszczane, gdy kolejka urządzeń się przepełni". To bardzo prawdopodobne, co się tam dzieje. Dzięki za wskazanie tego! – seeker

0
  • Każda z dwóch routerów ty mentionned może spaść pakiety jeśli jest przeciążenie,
  • i odbierania PC może spaść lub pakiety tęsknić, jak również w pewnych okolicznościach, takich jak przeciążenia.
2

Nawet jeśli send() bloki gdy bufor jest pełny send (pod warunkiem, że nie ustawić SOCK_NONBLOCK na gnieździe, aby umieścić go w trybie non-blokowanie) odbiornik musi nadal być wystarczająco szybki, aby obsłużyć wszystkie przychodzące pakiety. Jeśli odbiornik lub dowolny system pośredni jest wolniejszy od nadawcy, pakiety zostaną utracone podczas korzystania z protokołu UDP. Zauważ, że wolniej nie dotyczy tylko szybkości interfejsu sieciowego, ale także całego stosu sieci plus aplikacji przestrzeni użytkownika.

W twoim przypadku jest całkiem możliwe, że odbiornik odbiera wszystkie pakiety, ale nie może obsłużyć ich wystarczająco szybko w przestrzeni użytkownika. Możesz to sprawdzić, rejestrując i analizując ruch przez tcpdump lub wireshark.

Jeśli nie chcesz tracić pakietów, przełącz się na TCP.

0

Jak napisał jeden z powyższych postów, UDP to prosty protokół datagramowy, który nie gwarantuje dostawy. Z powodu lokalnej maszyny, urządzeń w sieci itp. To jest powód, dla którego wielu obecnych programistów zaleci, jeśli chcesz niezawodność, przełączyć się na TCP. Jednakże, jeśli naprawdę chcesz trzymać się protokołu UDP i istnieje wiele ważnych powodów, aby to zrobić, musisz znaleźć bibliotekę, która pomoże ci zagwarantować dostawę. Poszukaj projektów SS7, szczególnie w telefonicznych interfejsach API, w których protokół UDP służy do przesyłania informacji głosowych, danych i sygnalizacji. Dla Twojej wyłącznej aplikacji mogę zasugerować bibliotekę UDP. http://enet.bespin.org/

Powiązane problemy