Envoyer un fichier binary en réponse HTTP à l’aide de sockets C

J’essaie d’envoyer un fichier binary (image png) en réponse http.

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); } } 

mais mon navigateur ne comprend pas ceci = (Qu’est-ce que je fais mal exactement?

UPD: J’ai essayé d’envoyer des données texte – tout va bien. Mais les données binarys échouent

Le problème est que votre corps de message est traité comme une chaîne de texte à terminaison nulle (vous utilisez strcat et strlen dessus), alors que ce n’en est pas une: il s’agit de données binarys (un fichier PNG). Par conséquent, strcat et strlen s’arrêtent tous les deux sur le premier octet 0 de l’image (généralement assez tôt).

Votre programme est même en train d’imprimer le corps de la réponse: notez qu’il donne l’en-tête correct, mais qu’une fois que l’en-tête PNG (données binarys) démarre, il ne rest plus que quelques octets.

  1. La ligne strcat(reply, buffer) , où le buffer contient potentiellement 0 octet. Changez-le en memcpy(reply+strlen(header), buffer, fileLen) .
  2. La ligne d’ send(client, reply, strlen(reply), 0) , où la reply contient potentiellement 0 octet. Pré-calculez la longueur de la réponse ou remplacez strlen par strlen(header)+fileLen .

Un autre problème est que vous ne fermez pas la connexion lorsque vous avez terminé. Le navigateur attend donc pour toujours. Vous avez besoin de cela, après send :

 close(client); 

Le protocole HTTP spécifie qu’il attend “\ r \ n” au lieu de “\ n”. Essayez ça. 🙂

 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 

J’ai essayé de suivre ce que vous avez fait mais je ne pouvais pas le faire fonctionner. Au lieu de cela, j’ai trouvé plus facile d’envoyer simplement l’en-tête et le fichier séparément.

par exemple

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