2011-03-31 44 views
6

Estoy tratando de enviar un archivo binario (imagen png) en respuesta HTTP.Enviar archivo binario en respuesta HTTP usando sockets C

FILE *file; 
char *buffer; 
int fileLen; 

//Open file 
file = fopen("1.png", "rb"); 
if (!file) 
{ 
    return; 
} 

//Get file length 
fseek(file, 0, SEEK_END); 
fileLen=ftell(file); 
fseek(file, 0, SEEK_SET); 

//Allocate memory 
buffer=(char *)malloc(fileLen+1); 
if (!buffer) 
{ 
    fprintf(stderr, "Memory error!"); 
    fclose(file); 
    return; 
} 

//Read file contents into buffer 
fread(buffer, fileLen, 1, file); 
fclose(file); 
//free(buffer); 




char header[102400]; 

sprintf(header, 
"HTTP/1.1 200 OK\n" 
"Date: Thu, 19 Feb 2009 12:27:04 GMT\n" 
"Server: Apache/2.2.3\n" 
"Last-Modified: Wed, 18 Jun 2003 16:05:58 GMT\n" 
"ETag: \"56d-9989200-1132c580\"\n" 
"Content-Type: image/png\n" 
"Content-Length: %i\n" 
"Accept-Ranges: bytes\n" 
"Connection: close\n" 
     "\n", fileLen); 

char *reply = (char*)malloc(strlen(header)+fileLen); 
strcpy(reply, header); 
strcat(reply, buffer); 

printf("msg %s\n", reply); 


//return 0; 
int sd = socket(PF_INET, SOCK_STREAM, 0); 

struct sockaddr_in addr; 
bzero(&addr, sizeof(addr)); 
addr.sin_family = AF_INET; 
addr.sin_port = htons(8081); 
addr.sin_addr.s_addr = INADDR_ANY; 

if(bind(sd,&addr,sizeof(addr))!=0) 
{ 
    printf("bind error\n"); 
} 

if (listen(sd, 16)!=0) 
{ 
    printf("listen error\n"); 
} 

for(;;) 
{ 
    int size = sizeof(addr); 
    int client = accept(sd, &addr, &size); 

    if (client > 0) 
    { 
     printf("client connected\n"); 
     send(client, reply, strlen(reply), 0); 
    } 
} 

pero mi navegador no entender esto = (¿Qué estoy haciendo mal exactamente

UPD: He intentado enviar datos de texto - su visto bueno embargo, los datos binarios falla

Respuesta

7

El problema es que su cuerpo del mensaje está siendo tratado como una cadena de texto terminada en cero (se utiliza strcat y strlen en él), cuando no es uno: se trata de datos binarios (un archivo PNG). Por lo tanto, strcat y strlen se detienen en el primer byte de 0 en la imagen (generalmente bastante temprano).

Su programa incluso está imprimiendo el cuerpo de la respuesta: observe que da el encabezado correcto, pero que una vez que se inicia el encabezado PNG (datos binarios), solo hay unos pocos bytes.

  1. La línea strcat(reply, buffer), donde buffer contiene potencialmente 0 bytes. Cámbielo a memcpy(reply+strlen(header), buffer, fileLen).
  2. La línea send(client, reply, strlen(reply), 0), donde reply contiene potencialmente 0 bytes. Precalcule la longitud de la respuesta, o reemplace el strlen con strlen(header)+fileLen.

Otro error es que no está cerrando la conexión cuando haya terminado, por lo que el navegador esperará por siempre. Esto es necesario, después de send:

close(client); 
+0

Tenga en cuenta que esto no arreglará realmente la impresión de depuración que haya introducido, ya que usa printf y se detendrá cuando llegue al byte nulo. Pero el comportamiento del socket será correcto; Probé esto en un navegador web y funcionó. – mgiuca

1

El protocolo HTTP?. especifica que espera "\ r \ n" en lugar de "\ n". Trate de eso. :)

+0

No, eso no ayudó. Intenté enviar datos de texto; está bien con "\ n". Pero los datos binarios fallan – spe

+0

Windows convierte automáticamente \ n a \ r \ n en la salida – dns

0
strcat(reply, buffer); // this is incorrect, because png(buffer) may contain zero byte 
send(client, reply, strlen(reply), 0); 
strlen(reply) // this is incorrect, because png may contain zero byte 
+0

No solo eso; Observe que el 'strcat' del búfer a la respuesta también falla cuando llega a un byte nulo: vea mi respuesta. – mgiuca

0

He intentado seguir lo que hizo, pero no pude conseguir que funcione. En cambio, me resultó más fácil simplemente enviar el encabezado y el archivo por separado.

p. Ej.

send(client, header, strlen(header), 0); 
send(client, buffer, fileLen + 1, 0); 
Cuestiones relacionadas