2010-06-16 35 views
8

Necesito leer desde un socket AF_UNIX a un buffer usando la función read desde C, pero no conozco el tamaño del buffer.Leer desde el socket

Creo que la mejor manera es leer N bytes hasta que la lectura devuelva 0 (no más escritores en el socket). ¿Es esto correcto? ¿Hay alguna forma de adivinar el tamaño del buffer escrito en el socket?

Estaba pensando que un socket es un archivo especial. Abrir el archivo en modo binario y obtener el tamaño me ayudaría a saber el tamaño correcto para dar al búfer?

Soy un nuevo C, así que tenlo en cuenta.

Respuesta

14

De manera común es usar ioctl(..) para consultar FIONREAD del socket que devolverá la cantidad de datos disponibles.

int len = 0; 
ioctl(sock, FIONREAD, &len); 
if (len > 0) { 
    len = read(sock, buffer, len); 
} 
+0

Hola, y gracias. ¿Cuál es el cuarto argumento en lectura? – Donovan

+1

@Alberto, ah, eso es un error tipográfico. Solo debe ser 3 para leer, escribí 'recv' primero ... – epatel

0

tiene la razón, si no conoce el tamaño de la entrada solo puede leer un byte cada vez y anexarlo a un búfer más grande.

0

Lectura de n bytes leídos hasta que los devuelve 0

Sí!

Un detalle añadido. Si el emisor no cierra la conexión, el socket simplemente bloqueará, en lugar de regresar. Un socket sin bloqueo devolverá -1 (con errno == EAGAIN) cuando no haya nada que leer; ese es otro caso.

¿Abrir el archivo en modo binario y obtener el tamaño me ayudaría a saber el tamaño correcto para dar al búfer?

Nope. Los zócalos no tienen un tamaño. Supongamos que envía dos mensajes por la misma conexión: ¿Cuánto dura el archivo?

1

creo que la mejor manera es leer N bytes hasta que la lectura devuelve 0 (no hay más escritores en el zócalo). ¿Es esto correcto?

0 significa EOF, otro lado ha cerrado la conexión. Si el otro lado de la comunicación cierra la conexión, entonces es correcto.

Si la conexión no está cerrada (transferencias múltiples a través de la misma conexión, protocolo de conversación), entonces el caso es un poco más complicado y el comportamiento generalmente depende de si tiene sockets SOCK_STREAM o SOCK_DGRAM.

Los sockets de datagramas ya están delimitados para usted por el sistema operativo.

Los sockets Stream no delimitan los mensajes (todos los datos son un flujo de bytes opaco) y si lo desea, debe implementarlos en el nivel de aplicación: por ejemplo, definiendo un campo de tamaño en la estructura del encabezado del mensaje o usando un delimitador \ n 'para mensajes de texto de una sola línea). En el primer caso, primero leería el encabezado, extraería la longitud y usaría la longitud para leer el resto del mensaje. En otro caso, lea la secuencia en el búfer parcial, busque el delimitador y extraiga del búfer el mensaje que incluye el delimitador (puede que necesite mantener el búfer parcial ya que dependiendo del protocolo se pueden recibir varios comandos con un solo recv()/lectura ()).

¿Hay una manera de adivinar el tamaño de la memoria intermedia está escrito en la toma?

Para las tomas continuas, no hay una manera confiable ya que la otra parte de la comunicación podría estar aún en proceso de escritura de datos. Imagine el caso bastante normal: el buffer de socket es 32K y se está escribiendo 128K. La aplicación de escritura bloquearía dentro de send()/write(), el sistema operativo en espera de que la aplicación de lectura lea los datos y, por lo tanto, libere espacio para la próxima porción de datos escritos.

Para conectores de datagramas, uno normalmente conoce el tamaño del mensaje de antemano. O uno puede intentar (nunca lo hice yo mismo) recvmsg (MSG_PEEK) y si el MSG_TRUNC está en el msghdr.msg_flags devuelto, intente aumentar el tamaño del búfer.

2

Una manera de leer una cantidad desconocida de la toma evitando al mismo tiempo el bloqueo podría ser para sondear() un socket no bloqueante para los datos.

E.g.

char buffer[1024]; 
int ptr = 0; 
ssize_t rc; 

struct pollfd fd = { 
    .fd = sock, 
    .events = POLLIN 
}; 

poll(&fd, 1, 0); // Doesn't wait for data to arrive. 
while (fd.revents & POLLIN) 
{ 
    rc = read(sock, buffer + ptr, sizeof(buffer) - ptr); 

    if (rc <= 0) 
     break; 

    ptr += rc; 
    poll(&fd, 1, 0); 
} 

printf("Read %d bytes from sock.\n", ptr); 
Cuestiones relacionadas