[C] Probleme avec un Pipe

Probleme avec un Pipe [C] - C - Programmation

Marsh Posté le 27-09-2008 à 14:45:38    

Bonjour,
Je dois ecrire une programme qui lance 2 processus : 1 qui lit qq chose au clavier et qui l'envoie par la pipe (write) et l'autre qui recupere les caracteres a la sortie (read) et qui les affiche a l'ecran...
 

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. int main()
  7. {
  8. char *end = "$";
  9. int fd[2];
  10. pipe(fd);
  11. perror("Erreur (pipe): " );
  12. int p = fork();
  13. if(p!=0)
  14.  {
  15.  perror("Erreur (fork): " );
  16.  char tmp[10];
  17.  printf("Veuillez rentrer une suite de chaines de caracteres terminée par une chaine vide :" );
  18.  do
  19.   {
  20.   if(fgets(tmp,sizeof(tmp),stdin)==NULL) printf("erreur fgets" );
  21.   write(fd[1],tmp,strlen(tmp)+1);
  22.   perror("Erreur (write): " );
  23.   }while(strlen(tmp));
  24.  write(fd[1],tmp,sizeof(*tmp));
  25.  }
  26. if(p==0)
  27.  {
  28.  char tmp2[1];
  29.  do
  30.   {
  31.   if(read(fd[0],tmp2,1))
  32.    {
  33.    perror("Erreur (read): " );
  34.    printf(tmp2);
  35.    }
  36.   }while(strcmp(tmp2,end));
  37.  }
  38. }


 
 
j'ai le droit à cette magnifique erreur :
Erreur (write): : Invalid or incomplete multibyte or wide character
Erreur (read): : Illegal seek
Erreur (read): : Invalid or incomplete multibyte or wide character
Erreur (read): : Invalid or incomplete multibyte or wide character
Erreur (read): : Invalid or incomplete multibyte or wide character
 
que je ne comprends pas trop ... donc si quelqu'un aurait une idee ...
 
merci d'avance  :)  
 

Reply

Marsh Posté le 27-09-2008 à 14:45:38   

Reply

Marsh Posté le 27-09-2008 à 16:40:20    

j'ai améliorer un peu le truc :
 

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. int main()
  7. {
  8. char *end = "$";
  9. int fd[2];
  10. pipe(fd);
  11. perror("Erreur (pipe): " );
  12. int p = fork();
  13. if(p!=0)
  14.  {
  15.  close(fd[0]);
  16.  //perror("Erreur (fork): " );
  17.  char tmp[30];
  18.  //printf("Veuillez rentrer une suite de chaines de caracteres terminée par une chaine vide :" );
  19.  do
  20.   {
  21.   if(fgets(tmp,strlen(tmp),stdin)==NULL) printf("erreur fgets" );
  22.   int a = strlen(tmp);
  23.   printf("lg :%d",a);
  24.   write(fd[1],tmp,strlen(tmp));
  25.   perror("Erreur (write): " );
  26.   }while(strlen(tmp)!=1);
  27.  write(fd[1],end,strlen(end));
  28.  }
  29. if(p==0)
  30.  {
  31.  close(fd[1]);
  32.  char tmp2[2];
  33.  do
  34.   {
  35.   if(read(fd[0],tmp2,2))
  36.    {
  37.    perror("Erreur (read): " );
  38.    printf(tmp2);
  39.    }
  40.   }while(strcmp(tmp2,end));
  41.  }
  42. }


 
 
 
maintenant voilà l'erreur :
Erreur (pipe): : Success
lol
Erreur (write): : Illegal seek
lg :4Erreur (read): : Illegal seek
Erreur (read): : Invalid or incomplete multibyte or wide character
lo������p���Ŀ4��o��p��
plop
Erreur (write): : Illegal seek
Erreur (write): : Illegal seek
lg :3lg :2Erreur (read): : Invalid or incomplete multibyte or wide character
Erreur (read): : Invalid or incomplete multibyte or wide character
Erreur (read): : Invalid or incomplete multibyte or wide character
������p���Ŀ4��o��p���Ŀpl������p���Ŀ4��o��p���Ŀop������p���Ŀ4��o��p��
 
Erreur (write): : Illegal seek
lg :1ldk@LdK-virtualMachine:~/sgp$ Erreur (read): : Invalid or incomplete multibyte or wide character
p������p���Ŀ4��o��p��
 

Reply

Marsh Posté le 27-09-2008 à 17:59:58    

elldekaa a écrit : a écrit :


Code :
  1. char tmp[30];
  2. ...
  3. fgets(tmp,strlen(tmp),stdin)






Le contenu de tmp n'est pas défini donc strlen(tmp) non plus. Essai avec fgets(tmp,30,stdin)en vérifiant avant dans le man comment est géré \0  par fgets, faudra peut-être mettre 29.
Prévois aussi un tampon plus grand pour la lecture avec toujours de la place pour \0.

Message cité 1 fois
Message édité par ptitchep le 27-09-2008 à 18:01:31

---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 27-09-2008 à 19:14:51    

ptitchep a écrit :


Le contenu de tmp n'est pas défini donc strlen(tmp) non plus. Essai avec fgets(tmp,30,stdin)en vérifiant avant dans le man comment est géré \0  par fgets, faudra peut-être mettre 29.
Prévois aussi un tampon plus grand pour la lecture avec toujours de la place pour \0.


 
 
merci ça marche bien maintenant ...
juste un dernier soucis : je voudrais que les processus s'arrete lorsque une chaine vide est taper au clavier :
ma solution est d'envoyer dans le tube le caractere special "$" et ainsi arreter le processus fils ...
 
je voudrais trouver une solution plus propre (parce que actuellement si je rentre une chaine de caractere avec un "$" dedans le programme se termine.
donc si quelqu'un aurait une idee ...
 
 
 
 

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. int main()
  7. {
  8. char *end = "$"; // caractere "signal de fin"
  9. int tube[2];  // descripteur du tube
  10. if(pipe(tube)==-1) printf("erreur pipe" );
  11. //perror("Erreur (pipe): " );
  12. int p = fork();
  13. if(p==-1) printf("erreur fork" );
  14. if(p!=0)
  15.  {
  16.  close(tube[0]);
  17.  //perror("Erreur (fork): " );
  18.  char tmp[255];
  19.  printf("Veuillez rentrer une suite de chaines de caracteres terminée par une chaine vide : \n" );
  20.  do
  21.   {
  22.   if(fgets(tmp,255,stdin)==NULL) printf("erreur fgets" );
  23.   //int i = strlen(tmp);
  24.   //printf("lg: %d",i);
  25.   if(write(tube[1],tmp,strlen(tmp))==-1) printf("erreur write" );
  26.   }while(strlen(tmp)!=1);
  27.  if(write(tube[1],end,strlen(end))==-1) printf("erreur write" );
  28.  }
  29. if(p==0)
  30.  {
  31.  close(tube[1]);
  32.  char tmp2[1];
  33.  int tr;
  34.  while(strcmp(tmp2,end)!=0)
  35.   {
  36.   tr = read(tube[0],tmp2,1);
  37.   if(tr == -1) printf("erreur read" );
  38.   if(tr != 0) printf("%c",*tmp2);
  39.   }
  40.  }
  41. }

Message cité 1 fois
Message édité par elldekaa le 27-09-2008 à 19:19:38
Reply

Marsh Posté le 27-09-2008 à 20:35:26    

Avec un signal?
 

Code :
  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include <signal.h>
  7. int main()
  8. {
  9.     int fd[2];
  10.     int p;
  11.     if(pipe(fd)==-1)
  12.         perror("Erreur (pipe): " );
  13.     p = fork();
  14.     if (p==-1)
  15.     {
  16.         perror ("Erreur (fork): ";);
  17.         return -1;
  18.     }
  19.     if(p!=0)
  20.     {
  21.         int a;
  22.         char tmp[30];
  23.         close(fd[0]);
  24.         printf("chaine:n" );
  25.         do
  26.         {
  27.             fgets(tmp,29,stdin);
  28.             a = strlen(tmp);
  29.              if(write(fd[1],tmp,a+1)==-1)
  30.                 perror("Erreur (write): " );
  31.         }while(a>1);
  32.         kill (p,SIGTERM);
  33.     }
  34.     else
  35.     {
  36.         char tmp2[30];
  37.         close(fd[1]);
  38.         while(1)
  39.         {
  40.             if(read(fd[0],tmp2,30)==-1)
  41.                    perror("Erreur (read): " );
  42.             printf(tmp2);
  43.         }
  44.     }
  45.     return 0;
  46. }


---------------
deluser --remove-home ptitchep
Reply

Marsh Posté le 27-09-2008 à 22:15:12    

elldekaa a écrit :


ma solution est d'envoyer dans le tube le caractere special "$" et ainsi arreter le processus fils ...
 
je voudrais trouver une solution plus propre (parce que actuellement si je rentre une chaine de caractere avec un "$" dedans le programme se termine.
donc si quelqu'un aurait une idee ...


 
Ce genre de problème existe depuis la création de TCP/IP => comment signaler une fin sans que cette fin arrive "par erreur".
 
La solution la plus efficace est de donner un couple, par exemple "ab", qui signifie "arrêt".
Mais comment éviter de recevoir par erreur "ab" si par exemple l'émetteur envoie la chaine "abréviation" ? Ben tout simplement en dupliquant la lettre "a".
Donc si l'émetteur envoie "abréviation", le récepteur recevra "aabréviation". En lisant le premier "a" doublé il saura ce que c'est et enlèvera le "a" de trop. Mais s'il reçoit un simple "ab", alors cela voudra dire que c'est la fin.
 
Mécanisme primitif mais qui fonctionne tout le temps...


---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 27-09-2008 à 23:29:49    

Sve@r a écrit :


 
Ce genre de problème existe depuis la création de TCP/IP => comment signaler une fin sans que cette fin arrive "par erreur".
 
La solution la plus efficace est de donner un couple, par exemple "ab", qui signifie "arrêt".
Mais comment éviter de recevoir par erreur "ab" si par exemple l'émetteur envoie la chaine "abréviation" ? Ben tout simplement en dupliquant la lettre "a".
Donc si l'émetteur envoie "abréviation", le récepteur recevra "aabréviation". En lisant le premier "a" doublé il saura ce que c'est et enlèvera le "a" de trop. Mais s'il reçoit un simple "ab", alors cela voudra dire que c'est la fin.
 
Mécanisme primitif mais qui fonctionne tout le temps...


 
j'imagine que ça doit bien fonctionner mais je ne vois pas comment l'appliquer dans mon cas vu que j'envoie chaque phrase en entier dans le pipe et que je recois caractere par caractere ...
j'vais quand meme y reflechir et de toute facon je garde ta méthode en memoire pour quand j'en aurais besoin ; )
merci !

Reply

Marsh Posté le 27-09-2008 à 23:59:42    

ptitchep a écrit :

Avec un signal?


 
Marche nickel ! merci : )
 :D  

Reply

Marsh Posté le 28-09-2008 à 00:07:36    

et dans le cas où ce ne sont pas 2 processus pere-fils (cad quand ils ne sont pas lancés dans le meme terminal) ??

Reply

Marsh Posté le 28-09-2008 à 13:15:04    

C'est normal que tu ne teste pas le write avant de faire le perror ?

Reply

Marsh Posté le 28-09-2008 à 13:15:04   

Reply

Marsh Posté le 28-09-2008 à 14:08:15    

matafan a écrit :

C'est normal que tu ne teste pas le write avant de faire le perror ?


 
c'est fait dans la derniere version  ;)  

Reply

Marsh Posté le 28-09-2008 à 14:37:58    

elldekaa a écrit :

j'imagine que ça doit bien fonctionner mais je ne vois pas comment l'appliquer dans mon cas vu que j'envoie chaque phrase en entier dans le pipe et que je recois caractere par caractere ...


Ben tu traites la phrase avant de l'envoyer et à la réception tu gères un cas particulier si tu reçois le caractère "a" (dans l'exemple "ab" )...

elldekaa a écrit :

et dans le cas où ce ne sont pas 2 processus pere-fils (cad quand ils ne sont pas lancés dans le meme terminal) ??


L'envoi d'un signal (kill()) marche aussi même sur des processus non liés père/fils. Faut juste que le processus qui envoie le signal connaisse le pid du processus cible (et aussi qu'il soit le propriétaire)...


Message édité par Sve@r le 28-09-2008 à 14:38:17

---------------
Vous ne pouvez pas apporter la prospérité au pauvre en la retirant au riche.
Reply

Marsh Posté le 29-09-2008 à 09:30:53    

Je vais peut-être dire une connerie (enfin je pense pas, mais bon), mais pour ton histoire de fermeture je ne comprend pas trop le problème. Quand le producteur détecte une ligne vide, il close() le pipe. Ca aura pour effet d'arrêter la lecture dans le consomateur (read() retourne 0).
 
Envoyer un truc spécial dans le pipe, ça ne se justifie que si tu veux une "connexion" persistante.

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed