2010-03-30 12 views
7

Usando las API de socket UNIX en Linux, ¿hay alguna manera de garantizar que leo un paquete UDP y solo un paquete UDP? Actualmente estoy leyendo paquetes de un socket no bloqueante usando recvmsg, con un tamaño de buffer un poco más grande que el MTU de nuestra red interna. Esto debería garantizar que siempre pueda recibir el paquete UDP completo, pero no estoy seguro de poder garantizar que nunca recibiré más de un paquete por llamada recvmsg, si los paquetes son pequeños.¿puedo leer exactamente un paquete UDP de un socket?

Las páginas del manual recvmsg hacen referencia a la opción MSG_WAITALL, que intenta esperar hasta que se llene el búfer. No estamos usando esto, ¿eso implica que Recvmsg siempre regresará después de leer un datagrama? ¿Hay alguna manera de garantizar esto?

Idealmente me gustaría una solución cross-UNIX, pero si eso no existe ¿hay algo específico de Linux?

+1

MSG_WAITALL es para sockets orientados a flujo: http://linux.die.net/man/3/recvmsg Como ya se ha respondido, recv/send() funciona usando datagramas completos para sockets orientados a datagramas. – Ioan

Respuesta

12

recvmsg le devolverá un paquete, y será el paquete completo (siempre que el búfer que proporcione sea lo suficientemente grande).

De the POSIX documentation:

La función recvmsg() recibirán un mensaje de una conexión de modo o socket en modo sin conexión.

"un mensaje" significa exactamente un mensaje (o paquete), y,

Para conectores basados ​​en mensajes, tales como SOCK_DGRAM y SOCK_SEQPACKET, el mensaje completo se leerán en una sola operación.

+0

Si hay fragmentación. ¿'' 'Recievemsg''' devolverá datos solo después de que se reconstruye todo el paquete? – Artium

+0

Artium: Sí, esto lo realiza el sistema operativo y el espacio de usuario solo verá los paquetes ensamblados y no los fragmentos. Eso significa que el SO mantendrá un paquete fragmentado recibido durante algún tiempo esperando el resto de los fragmentos. –

0

Una de las opciones (opción digo) es el uso de pcap_next utilizando libpcap y desmontarlo para ver si es un paquete UDP. Usted puede hacer esto con:

/* jump pass the ethernet header */ 
ipdata = (struct ip*)(packet + sizeof(struct ether_header)); 
length -= sizeof(struct ether_header); 

(Tomado de tcpdump)

y luego probar la estructura ip para ver si es un paquete UDP haciendo:

if (ipdata->ip_p == IPPROTO_UDP) 

Y si esto falla , sigue haciendo bucles (llamando a pcap_next) hasta que obtengas tu paquete udp. Por supuesto, la extracción del datagrama udp es más difícil de esta manera, pero te permite entrar en el interior del paquete bastante bien. Consulte la fuente tcpdump para ver cómo quitar la información y qué sale.

Cuestiones relacionadas