• [^] # Re: Details

    Posté par . En réponse au message [C Posix] Histoire de fork de pipe et de select. É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);
    }