IPC utilisant fork () et pipe ()

J’essaie de simuler une conversation entre un appelant et un récepteur utilisant des tuyaux. Je transforme un processus et fait en sorte que le parent traite le destinataire et que l’enfant traite l’appelant.

Voici le code:

#include  #include  #include  #include  #include  #define BUF_LEN 25 #define READ_END 0 #define WRITE_END 1 int main() { int fd[2]; if (pipe(fd) == -1) { fprintf(stderr, "Pipe failed"); return 1; } pid_t pid = fork(); if (pid  0) { close(fd[WRITE_END]); char buffer[BUF_LEN + 1] = ""; do { read(fd[READ_END], buffer, sizeof buffer); if (strcmp(buffer, "")) { printf("Received %s\n", buffer); } strcpy(buffer, ""); } while (strcmp(buffer, "Bye!")); close(fd[READ_END]); } else { close(fd[READ_END]); // const char *msg = "Hello"; char buffer[BUF_LEN + 1] = ""; bool end_call = false; do { printf("Caller: "); fgets(buffer, sizeof buffer, stdin); if (strcmp(buffer, "Bye!")) { end_call = true; } // printf("Sent %s\n", buffer); write(fd[WRITE_END], buffer, strlen(buffer) + 1); } while (!end_call); close(fd[WRITE_END]); } return 0; } 

Mais quand je lance ceci, j’obtiens cette sortie inattendue:

 Caller: Hi Received Hi HI Hello Bye! ^C 

Le récepteur cesse de fonctionner, il ne reçoit pas les entrées que je donne. De plus, des nouvelles lignes apparaissent dans la sortie. Pourquoi cela se passe-t-il?

Edit: Comme indiqué par Dmisorting, j’ai changé le test strcmp dans l’appelant et l’instruction printf dans le récepteur.

 #include  #include  #include  #include  #include  #define BUF_LEN 25 #define READ_END 0 #define WRITE_END 1 int main() { int fd[2]; if (pipe(fd) == -1) { fprintf(stderr, "Pipe failed"); return 1; } pid_t pid = fork(); if (pid  0) { close(fd[WRITE_END]); char buffer[BUF_LEN + 1] = ""; do { read(fd[READ_END], buffer, sizeof buffer); if (strcmp(buffer, "")) { printf("Received %s", buffer); } strcpy(buffer, ""); } while (strcmp(buffer, "Bye!")); close(fd[READ_END]); } else { close(fd[READ_END]); // const char *msg = "Hello"; char buffer[BUF_LEN + 1] = ""; bool end_call = false; do { printf("Caller: "); fgets(buffer, sizeof buffer, stdin); if (!strcmp(buffer, "Bye!")) { end_call = true; } // printf("Sent %s\n", buffer); write(fd[WRITE_END], buffer, strlen(buffer) + 1); } while (!end_call); close(fd[WRITE_END]); } return 0; } 

Mais il ne sort toujours pas après avoir reçu “Bye!”.

 Caller: hi Received hi Caller: Hello Received Hello Caller: Bye! Received Bye! Caller: Bye! Received Bye! Caller: ^C 

Le strcmp () renvoie 0 en cas de succès. Mais il y a aussi plusieurs autres problèmes avec votre code:

  1. La chaîne ne sera jamais égale à “Bye!”, Il y aura une nouvelle ligne attachée ainsi que le caractère nul indiquant la fin de la chaîne (total de 6 caractères).

  2. Les pipes utilisent des stream et non des “paquets”, vous ne savez jamais combien d’octets vous recevrez d’un appel à lire (). Il peut s’agir d’une chaîne incomplète ou, si les données sont envoyées très rapidement, vous pouvez coller deux chaînes l’une sur l’autre. Vous devez implémenter votre propre “protocole” pour parsingr les données hors du stream.

  3. Vous ne vérifiez pas si le tuyau était fermé de l’autre côté (read renvoie 0)

  4. Vous obtenez une nouvelle ligne supplémentaire dans la sortie car elle est attachée à la chaîne lue par fgets ()

  5. La sortie peut être perturbée parce que vous n’avez aucun contrôle sur le moment où les processus se dirigent vers la sortie standard (une sorte de condition de course mais elle ne se bloquera pas).

En raison de la nouvelle ligne capturée par fgets vous devez tester la condition de sortie pour Bye!\n qui inclut cette nouvelle ligne. strcmp(buffer, "Bye!\n")

Cela s’ajoute à la résolution du problème de négation signalé par @blackpen.

Votre programme a plusieurs problèmes.

Tout d’abord, lorsque fgets() lit une ligne, la nouvelle ligne à la fin est incluse (s’il y a suffisamment d’espace dans le tampon). Les nouvelles lignes supplémentaires que vous voyez sont parce que la chaîne que vous envoyez en contient une, puis vous en ajoutez une autre lorsque vous l’imprimez dans le récepteur. De plus, vous cherchez la chaîne "Bye!" pour décider quand quitter … mais la chaîne que vous obtenez est "Bye!\n" . Vous devez supprimer la nouvelle ligne à la fin de la chaîne lue dans stdin dans l’expéditeur ou tenir compte de la nouvelle ligne déjà présente dans la chaîne lors de son impression et dans vos comparaisons.

Deuxièmement, dans l’expéditeur, vous avez inversé votre logique lorsque vous vérifiez quand quitter: Vous définissez end_call = true; lorsque le buffer ne contient pas "Bye!" , au lieu de quand Cela provoque la sortie de l’expéditeur après l’envoi de la première chaîne plutôt que la mise en boucle (de même, la comparaison doit être corrigée pour tenir compte de la nouvelle ligne mentionnée ci-dessus). Ce n’est pas le récepteur qui s’arrête tôt, c’est l’expéditeur … le récepteur fonctionne pour toujours à cause du prochain numéro.

Dans le récepteur, vous effacez le tampon à la fin de votre boucle, juste avant de vérifier "Bye!" dans le test en boucle. Cela empêche la comparaison dans le test de boucle de trouver une correspondance, donc la boucle est infinie. Effacer le tampon au début de la boucle avant fgets() place. (Et encore une fois, corrigez la comparaison pour tenir compte de la nouvelle ligne à la fin).

Modifiez le test dans le client à la suivante. Cela permettra à l’enfant / parent de communiquer.

  if (!strcmp(buffer, "Bye!")) { 

Le client a newline dans le tampon qu’il lit (“Bye!” Suivi d’un caractère de nouvelle ligne). Cela ne correspond pas au test de sortie. Vous pouvez essayer de le supprimer.

  fgets(buffer, sizeof buffer, stdin); buffer[strlen(buffer)-1]='\0'; 

Du côté du serveur, ne pas initialiser le tampon (juste avant la vérification). Parce que cela réinitialiserait la chaîne que vous êtes sur le sharepoint vérifier.

  strcpy(buffer, ""); 

Si vous le souhaitez, vous pouvez le mettre juste avant de lancer la fonction de read .

Vous pouvez également entrer dans un problème de mise en mémoire tampon des problèmes (en faisant correspondre la condition de fin) et les conditions de course (tout en fermant fds) comme indiqué par d’autres réponses. Mais je suppose que c’est un exemple suffisant pour «apprendre». Bonne chance.