2010-03-23 11 views
6

Estoy trabajando en un servidor UDP creado con boost :: asio y comencé desde la personalización tutorial a mis necesidades. Cuando llamo al socket.receive_from(boost::asio::buffer(buf), remote, 0, error);, llena mi búfer con los datos del paquete, pero, si mi comprensión es correcta, se descartan los datos que no quepan en el búfer. Las llamadas posteriores a receive_from recibirán el siguiente datagrama disponible, por lo que me parece que hay una pérdida de datos sin siquiera un aviso. ¿Estoy entendiendo esto de la manera incorrecta?¿Puede boost :: asio solo recibir datagramas UDP completos?

He intentado leer una y otra vez la documentación de boost :: asio, pero no pude encontrar pistas sobre cómo se supone que debo hacer esto de la manera correcta. Lo que me gustaría hacer es leer una cierta cantidad de datos para poder procesarlos; si leer un datagrama completo es la única manera, puedo hacerlo, pero ¿cómo puedo estar seguro de no perder los datos que estoy recibiendo? ¿Qué tamaño de búfer debo usar para estar seguro? ¿Hay alguna manera de decir que mi buffer es demasiado pequeño y estoy perdiendo información?

Tengo que asumir que puedo estar recibiendo enormes datagramas por diseño.

Respuesta

7

Esto no es específico de impulsar; es solo cómo funcionan los conectores de datagramas. Debe especificar el tamaño del búfer, y si el paquete no cabe en el búfer, se truncará y no habrá forma de recuperar la información perdida.

Por ejemplo, el protocolo SNMP especifica que:

Una implementación de este protocolo no es necesario aceptar mensajes cuya longitud supera 484 octetos. Sin embargo, se recomienda que las implementaciones admitan datagramas más grandes siempre que sea factible.

En resumen: al diseñar su protocolo de comunicación, debe tener en cuenta que los datagramas pueden perderse o que se pueden truncar más allá de un tamaño específico.

+1

Eso es lo que pensé y solo necesitaba la confirmación de alguien con más experiencia en este tema. Hablé con el gerente de proyecto y me dio una estimación del tamaño máximo de los datagramas, aunque no hay un protocolo fijo. – Kjir

1

Use getsockopt con la opción SO_NREAD.

Desde la página de manual de Mac OS X:

SO_NREAD devuelve la cantidad de datos en el buffer de entrada que está disponible para ser recibida. Para sockets orientados a gramas de datos, SO_NREAD devuelve el tamaño del primer paquete; esto difiere del comando ioctl() FIONREAD que devuelve la cantidad total de datos disponibles.

+3

Hay un método disponible() en la clase boost :: asio :: ip :: udp :: socket, gracias por la sugerencia. – Kjir

3

Para IPv4, el campo de tamaño de datagrama en el encabezado UDP es de 16 bits, dando un tamaño máximo de 65,535 bytes; cuando resta 8 bytes para el encabezado, termina con un máximo de 65.527 bytes de datos. (Tenga en cuenta que esto requeriría la fragmentación del datagrama IPv4 adjunto independientemente de la MTU de la interfaz subyacente debido al campo de 16 bits de paquetes IPv4/fragmento).

Solo uso un buffer 64 KiB porque es un buen número redondo.

Tendrá que tener en cuenta que en el lado de la transmisión puede necesitar habilitar explícitamente la fragmentación si desea enviar datagramas más grandes que los que caben en la interfaz MTU. Desde mi Ubuntu 12.04 UDP (7) página de manual:

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. 
Cuestiones relacionadas