Forum Programmation.c [C Posix] Histoire de fork de pipe et de select

Posté par  (site Web personnel) .
Étiquettes : aucune
0
14
juin
2006
Bonjour amis inpactiens,

Je m'essaye a la programmation C posix et je me pose une petite question enfin surtout je rencontre un probleme :)
Je viens de faire un petit programme simple qui se resume à :
- Forker un processus.
- Ouvrir un pipe dans le processus parent qui envoie des données dans le processus enfant.
- Ouvrir un pipe dans le processus enfant qui renvoie les données transmise en majuscule (traitement simple de caracteres).

Afin de faire ca propre la legende posixienne voudrait que je fasse un select dans le processus parent pour switcher entre le moment d'envoyer les données dans le processus enfant et le moment d'ecrire les données sur STDOUT recu du processus enfant.

Mon petit programme sans le select marche actuellement comme ca :

http://pastebin.com/708367

(désoler obliger de prendre pastebin le forum meme avec les balise code et pre tiens absolument a me urlencode et c'est génant)

Ca marche mais a mon avis je risque des deadlock lors de gros flux de données, comme vous pouvez le voir j'ai commencé a déclarer ma struct pour le select mais je bloque un peu. La légende raconte :

* Fill up a fd_set structure with the file descriptors you want to know when data comes in on.
* Fill up a fd_set structure with the file descriptors you want to know when you can write on.

Mais eu concretement comment mettre ca en place dans ce genre de situation ?
Merci de votre aide qui me sera surement d'un grand secours !
  • # Details

    Posté par  (site Web personnel) . Évalué à 3.

    Tu as une accolade fermante en trop (et le probleme d'indentation qui va avec).

    Ensuite tu n'as potentiellement un probleme que si tu comptes envoyer plus de données qu'en recevoir : 512 -> MAXBUFFER

    Mais sinon sur le principe, le read est bloquant et tu lis un seul fd a la fois, donc tu n'as pas besoin de select dans ce cas précis.
    • [^] # Re: Details

      Posté par  (site Web personnel) . Évalué à 1.

      En faite le principe de mise en place du select m'interresse pas mal :).
      Et dans cet exemple que j'ai ecrit cela me permettrait de le comprendre facilement !

      Merci de ton aide :p
      • [^] # Re: Details

        Posté par  . Évalué à 2.

        Un peu de code vaut mieux que de longs discours:

        /* gcc -W -Wall -std=c99 -posix -pedantic posix.c */

        #define _BSD_SOURCE
        #define _ISOC99_SOURCE

        #include <stdlib.h> /* libc */
        #include <unistd.h> /* pipe(), fork(), *_FILENO ... */
        #include <stdio.h> /* printf(), BUFSIZ, ... */
        #include <ctype.h> /* toupper() */
        #include <string.h> /* memset() */
        #include <sys/types.h> /* pid_t, ... */
        #include <sys/wait.h>

        #define STRINGIFY(x)  #x
        #define STR(x)  STRINGIFY(x)
        #define ERR(c, f) #c "()::" #f  "() @ " __FILE__ ":" STR(__LINE__)

        static inline void _strtoupper(char *s)
        {
           do *s = toupper(*s); while (*s ++);
        }


        int main(void)
        {
           pid_t pid = 0;
           char buf[BUFSIZ];  /* buffer de lecture */
           int in[2], out[2]; /* les pipes */
           fd_set fd;
           struct timeval tmout;
           int run = 20; /* nombre de tours */
           int len = 0; /* retour de read */

           /* ouvre les pipe d'input/output */
           if (pipe(in) == -1) {
              perror(ERR(main, pipe)); exit(EXIT_FAILURE);
           }

           if (pipe(out) == -1) {
              perror(ERR(main, pipe)); exit(EXIT_FAILURE);
           }

           /* pipe[0] = lecture, pipe[1] = ecriture */

           switch ( (pid = fork()) ) {
              case -1: /* failed */
                 close(in[0]); close(in[1]);
                 close(out[0]); close(out[1]);
                 exit(EXIT_FAILURE);

              case 0: /* papa */
                 /* on veut ecrire dans l'input, et lire dans l'output (point de vue fiston) */
                 close(in[0]); close(out[1]);
                 if (dup2(out[0], STDIN_FILENO) == -1) {
                   perror(ERR(main, dup2)); exit(EXIT_FAILURE);
                 }
                 if (dup2(in[1], STDOUT_FILENO) == -1) {
                   perror(ERR(main, dup2)); exit(EXIT_FAILURE);
                 }

                 /* ecrit un message d'initialisation au bout de cinq secondes */
                 sleep(5);
                 printf("salut fiston !");
                 fflush(stdout);
              break;

              default: /* fiston */
                 /* on veut lire dans l'input, et ecrire dans l'output */
                 close(in[1]); close(out[0]);
                 if (dup2(in[0], STDIN_FILENO) == -1) {
                   perror(ERR(main, dup2)); exit(EXIT_FAILURE);
                 }
                 if (dup2(out[1], STDOUT_FILENO) == -1) {
                   perror(ERR(main, dup2)); exit(EXIT_FAILURE);
                 }
           }

           /* boucle de lecture/ecriture commune */
           while (run --) {
              /* une seconde de timeout */
              tmout.tv_sec = 1;
              tmout.tv_usec = 0;

              /* c'est pas portable de faire ca avec le vrai stdin, mais la c'est notre pipe */
              FD_SET(STDIN_FILENO, & fd);

              if (select(1, & fd, NULL, NULL, & tmout) == -1) {
                 perror(ERR(main, select)); exit(EXIT_FAILURE);
              }

              if (FD_ISSET(STDIN_FILENO, & fd)) {
                 memset(buf, '\0', sizeof(buf));

                 if ( (len = read(STDIN_FILENO, buf, sizeof(buf))) == -1) {
                   perror(ERR(main, read)); exit(EXIT_FAILURE);
                 }

                 if (len == 0) {
                   fprintf(stderr, "%s: connection morte\n", (pid) ? "fiston" : "papa");
                   break;
                 }
         
                 if (pid == 0) {
                   /* papa */
                   fprintf(stderr, "Le fiston a ecrit: %s\n", buf);
                   printf("met-moi ca en caps fiston...");
                   fflush(stdout);
                 } else {
                   /* fiston */
                   _strtoupper(buf);
                   printf("%s", buf);
                   fflush(stdout);
                 }
              } else {
                 fprintf(stderr, "%s: j'ai rien a faire !\n", (pid) ? "fiston" : "papa");
              }
           }

           /* normalement le fils creve toujours avant, mais soyons propre */
           if (pid == 0) wait(NULL);

           /* vu qu'on a branche les pipe sur stdin/out, cleanup automatique */
           exit(EXIT_SUCCESS);
        }
        • [^] # Re: Details

          Posté par  . Évalué à 2.

          Bon, j'ai un remord, même si c'est du code vite fait et premier jet, le _strtoupper est vraiment trop laid; remplace le plutôt par un truc comme ça:

          static inline void _strtoupper(char *s, size_t len)
          {
              if (! s || ! len) return;
              while (len --) s[len] = toupper(s[len]);
          }

          en utilisant la longueur renvoyée par read(2)...

          /!\ le paramètre len revient à strlen() + 1 là (read(2) compte le NUL final)

Suivre le flux des commentaires

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n’en sommes pas responsables.