Séparer les erreurs avec une commande ouverte lorsque vous essayez d’ouvrir un très grand fichier

Je prends un cours de réseautage à l’école et utilise C / GDB pour la première fois. Notre tâche consiste à créer un serveur Web qui communique avec un navigateur client. Je suis bien parti et peut ouvrir des fichiers et les envoyer au client. Tout va bien jusqu’à ce que j’ouvre un fichier très volumineux et ensuite je me trompe. Je ne suis pas un pro chez C / GDB, donc je suis désolé si cela me pose des questions stupides et que je ne suis pas capable de voir la solution moi-même, mais quand je regarde le kernel jeté,

if (-1 == (openfd = open(path, O_RDONLY))) 

Plus précisément, nous sums chargés d’ouvrir le fichier et de l’envoyer au navigateur client. Mon algorithme va:

  1. Open / Error catch
  2. Lire le fichier dans un tampon / erreur catch
  3. Envoyer le fichier

Nous avons également été chargés de veiller à ce que le serveur ne plante pas lors de l’envoi de fichiers très volumineux. Mais mon problème semble être de les ouvrir. Je peux envoyer tous mes fichiers plus petits très bien. Le fichier en question est de 29,5 Mo.

L’algorithme entier est:

 ssize_t send_file(int conn, char *path, int len, int blksize, char *mime) { int openfd; // File descriptor for file we open at path int temp; // Counter for the size of the file that we send char buffer[len]; // Buffer to read the file we are opening that is len big // Open the file if (-1 == (openfd = open(path, O_RDONLY))) { send_head(conn, "", 400, strlen(ERROR_400)); (void) send(conn, ERROR_400, strlen(ERROR_400), 0); logwrite(stdout, CANT_OPEN); return -1; } // Read from file if (-1 == read(openfd, buffer, len)) { send_head(conn, "", 400, strlen(ERROR_400)); (void) send(conn, ERROR_400, strlen(ERROR_400), 0); logwrite(stdout, CANT_OPEN); return -1; } (void) close(openfd); // Send the buffer now logwrite(stdout, SUC_REQ); send_head(conn, mime, 200, len); send(conn, &buffer[0], len, 0); return len; } 

Je ne sais pas si c’est juste un fait que je suis un novice Unix / C. Désolé si c’est le cas. = (Mais vous êtes très apprécié.

Plutôt que d’utiliser un tableau de longueur variable, essayez peut-être d’allouer la mémoire en utilisant malloc .

 char *buffer = malloc (len); ... free (buffer); 

Je viens de faire des tests simples sur mon système, et quand j’utilise des tableaux de longueur variable de grande taille (comme la taille avec laquelle vous avez des problèmes), je reçois également un SEGFAULT.

Il est possible que je ne comprenne pas bien ce que vous vouliez dire dans votre question, mais je pense que je devrais faire remarquer qu’en général, c’est une mauvaise idée d’essayer de lire le fichier en entier en cas de problème votre mémoire à gérer.

Il est plus judicieux d’allouer un tampon d’une taille spécifique, disons 8192 octets (enfin, c’est ce que j’ai tendance à faire beaucoup, de toute façon), et de toujours lire et envoyer autant de fois que nécessaire jusqu’à ce que 0 (et pas d’erreur) pour la fin du stream.

Je soupçonne que vous avez un stackoverflow (je devrais obtenir des points bonus pour utiliser ce terme sur ce site).

Le problème est que vous allouez le tampon pour tout le fichier sur la stack en même temps. Pour les fichiers plus volumineux, ce tampon est plus grand que la stack et la prochaine fois que vous essayez d’appeler une fonction (et donc d’y placer certains parameters), le programme se bloque.

Le plantage apparaît sur la ligne ouverte car l’allocation du tampon sur la stack n’écrit pas réellement de mémoire, il modifie simplement le pointeur de stack. Lorsque votre appel à ouvrir essaie de passer les parameters à la stack, le haut de la stack est maintenant saturé et cela provoque un plantage.

La solution est comme le suggèrent Platinum Azure ou Dreamlax, de lire les petits morceaux du fichier à la fois ou d’allouer votre tampon sur le segment de mémoire malloc ou new.

Vous allouez le tampon sur la stack, et il est beaucoup trop gros.

Lorsque vous allouez de l’espace de stockage sur la stack, le compilateur ne fait que diminuer le pointeur de la stack pour libérer autant d’espace (cela permet d’allouer la variable de stack à un temps constant). Il n’essaie pas de toucher à cette mémoire empilée. Ensuite, lorsque vous appelez open() , il essaie de mettre les parameters sur la stack et découvre qu’il a débordé la stack et meurt.

Vous devez soit opérer sur le fichier en morceaux, le mapper en mémoire ( mmap() ) ou le stockage malloc() . En outre, path doit être déclaré const char* .