2010-03-23 19 views
6

Pracuję na serwerze UDP zbudowanym z boost :: asio i zacząłem od tutorial dostosowując się do moich potrzeb. Gdy zadzwonię pod numer socket.receive_from(boost::asio::buffer(buf), remote, 0, error);, wypełni mój bufor danymi z pakietu, ale jeśli moje zrozumienie jest poprawne, to spowoduje to utratę wszelkich danych, które nie mieszczą się w buforze. Kolejne wywołania receive_from dostaną następny dostępny datagram, więc wygląda na to, że utracono dane nawet bez powiadomienia. Czy rozumiem to w niewłaściwy sposób?Czy mogę :: asio otrzymywać tylko pełne datagramy UDP?

Próbowałem czytać w kółko po dokumentacji boost :: asio, ale nie udało mi się znaleźć wskazówek, jak mam to zrobić we właściwy sposób. Chciałbym przeczytać pewną ilość danych, aby móc je przetworzyć; jeśli czytanie całego datagramu jest jedyną drogą, mogę sobie z tym poradzić, ale jak mogę się upewnić, że nie stracę danych, które otrzymuję? Jakiego rozmiaru bufora powinienem używać, aby mieć pewność? Czy jest jakiś sposób, aby powiedzieć, że mój bufor jest za mały i tracę informacje?

Muszę założyć, że mogę otrzymywać ogromne datagramy według projektu.

Odpowiedz

7

To nie jest specyficzne dla zwiększenia; tak działają gniazda datagramowe. Musisz określić rozmiar bufora, a jeśli pakiet nie pasuje do bufora, zostanie on obcięty i nie będzie możliwości odzyskania utraconych informacji.

Na przykład, protokół SNMP określa, że:

Implementacja tego protokołu nie musi akceptować wiadomości, których długość przekracza 484 oktetów. Zaleca się jednak, aby implementacje obsługiwały większe datagramy, o ile jest to możliwe.

W skrócie: należy wziąć to pod uwagę przy projektowaniu protokołu komunikacyjnego, że datagramy mogą zostać utracone lub mogą być obcięte powyżej określonego rozmiaru.

+1

Tak właśnie pomyślałem i potrzebowałem potwierdzenia od kogoś z większym doświadczeniem w tej kwestii. Rozmawiałem z kierownikiem projektu i dał mi oszacowanie maksymalnego rozmiaru datagramów, chociaż nie ma ustalonego protokołu. – Kjir

1

Użyj opcji getsockopt z opcją SO_NREAD.

Z Mac OS X podręcznika:

SO_NREAD zwraca ilość danych w buforze wejściowym, który jest dostępny do odbioru. Dla gniazd zorientowanych na dane grama, SO_NREAD zwraca rozmiar pierwszego pakietu - różni się on od komendy ioctl() FIONREAD, która zwraca całkowitą ilość dostępnych danych.

+3

Istnieje metoda available() w klasie boost :: asio :: ip :: udp :: socket, dzięki za sugestię. – Kjir

3

Dla IPv4 pole rozmiaru datagramu w nagłówku UDP ma 16 bitów, co daje maksymalny rozmiar 65 535 bajtów; kiedy odejmiesz 8 bajtów dla nagłówka, otrzymasz maksymalnie 65 527 bajtów danych. (Zauważ, że wymagałoby to fragmentacji otaczającego datagramu IPv4, niezależnie od bazowego MTU interfejsu z powodu 16-bitowego pola pakietu/długości IPv4.)

Używam tylko bufora 64 KiB, ponieważ jest to niezły numer okrągły.

Należy pamiętać, że po stronie nadawczej może być konieczne wyraźne włączenie fragmentacji, jeśli chcesz wysłać datagramy większe niż mieszczą się w MTU interfejsu. Z mojego Ubuntu 12.04 UDP (7) strona podręcznika:

By default, Linux UDP does path MTU (Maximum Transmission Unit) discov‐ 
    ery. This means the kernel will keep track of the MTU to a specific 
    target IP address and return EMSGSIZE when a UDP packet write exceeds 
    it. When this happens, the application should decrease the packet 
    size. Path MTU discovery can be also turned off using the IP_MTU_DIS‐ 
    COVER socket option or the /proc/sys/net/ipv4/ip_no_pmtu_disc file; see 
    ip(7) for details. When turned off, UDP will fragment outgoing UDP 
    packets that exceed the interface MTU. However, disabling it is not 
    recommended for performance and reliability reasons. 
Powiązane problemy