IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Pipe, fork & Select


Sujet :

C

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut Pipe, fork & Select
    Bonjour,

    je dois faire un programme qui contient deux processus qui communiquent via des pipes. Le processus fils doit à la fois pouvoir lire sur un pipe et écrire sur un autre. Concrètement le fils doit envoyer une commande au père, qui l'exécute et écrit le résultat sur un autre pipe, puis le fils doit de nouveau lire sur l'autre pipe le résultat pour l'afficher. Pour cela j'utilise select() de cette façon:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    pipe(pr);
    pipe(pw);
    ...
    fd_set r_fdset, w_fdset;
    FD_ZERO(&r_fdset);
    FD_ZERO(&w_fdset);
    FD_SET(pr[1], &w_fdset);
    FD_SET(pw[0], &r_fdset);
     
    max = (pr[1] > pw[0]) ? pr[1] : pw[0];
     
    while(1) {
        state = select(max+1, &r_fdset, &w_fdset, NULL, NULL);
     
        if(state == -1) perror("select");
        else if(state > 0) {
     
            if (FD_ISSET(pr[1], &w_fdset)) {
                printf("Ecriture\n");
            }
     
            if (FD_ISSET(pw[0], &r_fdset)) {
                printf("Lecture\n");
            }
        } else {
            printf("Rien\n");
        }
    }
     
    ...
    Le problème que j'ai est que le select() ne retourne jamais avec la lecture possible sur pw[0]. J'ai essayé beaucoup de chose mais j'obtiens toujours un Bad file descriptor.

    Merci pour voter aide.

  2. #2
    Membre expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 51
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Points : 3 352
    Points
    3 352
    Par défaut
    Salut,

    as-tu ouvert les deux pipes en lecture et en écriture (c'est obligatoire, même si tu n'utilises qu'un bout) dans le père et le fils ?

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    La fonction pipe() ouvre les deux pipes avant le fork(). Pour l'instant je ferme aucune des extrémités du pipe que ce soit dans le père ou dans le fils.

  4. #4
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Tu ne teste pas la valeur de retour de certaines fonctions (comme int pipe(int [2]) ).

    Ensuite, je ne suis pas sûr, mais select peut-il regarder deux tubes à la fois?
    Je dois avouer que je n'ai jamais eu à l'utiliser.

  5. #5
    Membre averti Avatar de cmoibal
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    361
    Détails du profil
    Informations personnelles :
    Localisation : Tunisie

    Informations forums :
    Inscription : Avril 2007
    Messages : 361
    Points : 414
    Points
    414
    Par défaut
    voici un example, mais en utilisant la methode poll():

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    #include <stdio.h>
    #include <fcntl.h>
    #include <poll.h>
    #define MAX_BUFF_SIZE 128
     
    int main(void){
        char buff[MAX_BUFF_SIZE + 1];
        char *buf = NULL;
        int fd = -1;
        int ret = -1;
        int len = 0;
        struct pollfd fdinfo[1];
     
        if((fd = open("/home/s/pipe", O_RDONLY)) == NULL) {
            printf("Error Opening File.\n");
            exit(1);
        }
     
        fdinfo[0].fd = fd;
        fdinfo[0].events = POLLIN|POLLPRI ;
     
        while(1)
        {
            ret = poll(fdinfo,1,-1);
            if (ret < 0) printf("\n\r error");
     
            if ( ((fdinfo[0].revents&POLLIN) == POLLIN) || ((fdinfo[0].revents&POLLPRI) == POLLPRI) )
            {
                len = read(fdinfo[0].fd, buff, MAX_BUFF_SIZE);
                if (len > 0){
                    buff[len] = '\0';
                    buf = (char *) calloc(1, len+1);
                    memcpy(buf, buff, len);
                    printf("\n read len %d\n %s",len, buf);
                    free(buf);
                 }
            }
     
        }
        return 0;
    }
    "La créativité est faites d'attention et de respect pour les petits faits de la vie."

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    En réalité je test la sortie de la fonction pipe. Mais pour plus de simplicité je ne l'ai pas mis dans le poste.

    Pour ce qui est de la fonction poll(), je suis contraint d'utiliser select() :/

    Merci

  7. #7
    Membre averti Avatar de cmoibal
    Profil pro
    Inscrit en
    Avril 2007
    Messages
    361
    Détails du profil
    Informations personnelles :
    Localisation : Tunisie

    Informations forums :
    Inscription : Avril 2007
    Messages : 361
    Points : 414
    Points
    414
    Par défaut
    Je pense que le problème est que select() ce bloque !!!

    timeout is an upper bound on the amount of time elapsed before select() returns. If both fields of the timeval structure are zero, then select() returns immediately. (This is useful for polling.) If timeout is
    NULL (no timeout), select() can block indefinitely.
    Il y a la structure suivante qu'il faut utiliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    struct timeval {
                   long    tv_sec;         /* seconds */
                   long    tv_usec;        /* microseconds */
               };
     
    /* Wait up to five seconds. */
               tv.tv_sec = 5;
               tv.tv_usec = 0;
    Est ce que ton programme se bloque ?
    "La créativité est faites d'attention et de respect pour les petits faits de la vie."

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    Si je fais un "ps -aux" je ne trouve pas de trace de mon programme, donc je pense qu'il sort et se termine "normalement".

    De plus le select() me renvoie le message d'erreur "Bad file descriptor" lorsque je test la valeur de sortie de select(). Ce qui veut dire que select() ne se bloque pas. Enfin je pense..

  9. #9
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Select est bloquant (sauf si on lui indique un temps de timeout).

    Mais ton select ne bloque pas car il retourne une erreur, "bad file descripteur" signifie que tu passe en paramètre à ton select un descripteur de tube invalide.

    Descripteur stocké dans pr[0], pr[1], pw[0] ou pw[1]

  10. #10
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    Oui, ça je l'avais compris
    Maintenant je cherche une solution, vu que mes tubes sont forcement ouverts..sinon les deux appels à pipe() auraient renvoyé une erreur.

  11. #11
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Essaye de faire le select sur un seul des descripteurs pour voir si le problème vient d'un des descripteurs et affiche le n° des descripteur et celui de max régulièrement.

    J'ai relu le man de select et il me semble que tu as tout fait correctement, donc à part afficher les valeurs des variables qui peuvent poser problème, je ne vois pas trop quoi faire.

    NB : Erreur bête, est-ce que tu n'aurais pas inversé les descripteurs de lecture et d'écriture?

    EDIT : non même pas, je suis vraiment perplexe.

  12. #12
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    Si je ne trompe pas on lit sur p[0] et on écrit sur p[1] non?
    J'ai mis pr[1] dans un fd_set qui va directement dans le bon argument de select() et pw[0] dans un autre fd_set qui va dans l'autre argument de select().

  13. #13
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 012
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 31
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 012
    Points : 23 145
    Points
    23 145
    Par défaut
    Franchement à part tenter de faire avec un seul descripteur de fichier pour savoir quel descripteur est invalide et vérifier si max a la bonne valeur...

    J'ai beau relire le man, je ne vois pas ce qui cloche.

    Peut être revérifier d'avoir tout inclus les bibliothèques correctement (?)

  14. #14
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    Pour ce qui est de la valeur de max, j'ai essayé de la faire recalculer à chaque itération, mais ça ne change rien.

    Lorsque j'utilise select() avec un fdset en lecture ou en écriture ça passe niquel. Quand j'utilise les deux en même temps, blocage et rien ne bouge.

  15. #15
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Il y a un truc qui me saute aux yeux tout de suite, c'est qu'il faut refaire FD_SET à chaque tour. Avant chaque appel à select(), pour être exact.

    select() se sert des mêmes sets pour savoir d'abord quels descripteurs il doit surveiller et pour indiquer, ensuite, lesquels se sont débloqués. Donc, les FD_SET effectués au préalable sont perdus une fois l'appel à select() terminé.

  16. #16
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    J'ai aussi tenté cette solution, sans succès. J'avoue que je ne comprend pas pourquoi select() déconne quand on lui donne 2 fd_set différents.

    Voici le code que j'ai essayé:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    int pr[2], pw[2], output_fd;
     
    	if (argc < 2) {
    		printf("ERREUR: Arguments invalides\n");
    		return EXIT_FAILURE;
    	}
     
    	if ((pipe(pw) < 0) || (pipe(pr) < 0) || (output_fd = open(FILE, O_WRONLY | O_CREAT, 0600)) < 0) {
    		perror("init");
    		return EXIT_FAILURE;
    	}
     
    	if (fork() > 0) {
    		int n, state, nfds = 0;
    		fd_set r_fdset, w_fdset;
    		struct timeval dt = {5, 0};
     
    		while (1) {
    			FD_ZERO(&r_fdset);
    			FD_ZERO(&w_fdset);
    			FD_SET(pr[1], &w_fdset);
    			FD_SET(pw[0], &r_fdset);
     
    			nfds = (pr[1] > pw[0]) ? pr[1] : pw[0];
    			state = select(nfds+1, &r_fdset, &w_fdset, NULL, &dt);
     
    			if (state == -1) {
    				perror("select()");
    				break;
    			} else if (state > 0) {
     
    				if (FD_ISSET(pw[0], &r_fdset)) {
    					char c[10];
     
    					read(pw[0], c, 5*sizeof(char));
    					printf("Arrive %s\n", c);
     
    					break;
    				}
     
    				if (FD_ISSET(pr[1], &w_fdset)) {
    					printf("Depart\n");
    					write(pr[1], "test", 5*sizeof(char));
     
    					/* Fermeture du pipe */
    					close(pr[1]);
    				}
    			} else {
    				printf("Timeout\n");
    				break;
    			}
    		}
     
     
    	} else { /* Executeur */		
    		char c[10];
    		int n;
     
    		n = read(pr[0], c, 5*sizeof(char));
    		printf("Choppe %s\n", c);
    		write(pw[1], c, n);
    	}
    Certains close() ont étés volontairement omis.
    Ce code ne fonctionne pas.

  17. #17
    Modérateur
    Avatar de Obsidian
    Homme Profil pro
    Développeur en systèmes embarqués
    Inscrit en
    Septembre 2007
    Messages
    7 372
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Développeur en systèmes embarqués
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2007
    Messages : 7 372
    Points : 23 628
    Points
    23 628
    Par défaut
    Il fonctionne en partie : ta boucle fait plusieurs tours mais tu ne t'en rends pas compte.

    D'abord, un pipe est doté d'un buffer. Par défaut, tu peux écrire jusqu'à 4096 octets dedans avant qu'il passe en mode bloquant si le lecteur ne lit pas en parallèle. Ça signifie que ton premier appel à select() va automatiquement se débloquer même si le processus fils n'a pas encore démarré. Bon, en l'occurrence, il commence par un read() donc le résultat est le même.

    Ensuite, ligne 46, tu fais un « close pr[1] », c'est-à-dire que tu refermes le tube dans lequel tu viens d'écrire. Au tour de boucle suivant, tu refais un select() sur le même descripteur. Son numéro est toujours dans le tableau parce qu'il n'y a pas de raison qu'il en ait disparu, mais il ne correspond plus à rien et select() se plaint en te renvoyant un « Bad File Descriptor ».

  18. #18
    Membre régulier
    Profil pro
    Inscrit en
    Juillet 2009
    Messages
    112
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2009
    Messages : 112
    Points : 90
    Points
    90
    Par défaut
    Je pensais que ça pouvait venir de là mais je n'en étais pas sûr.

    Néanmoins j'ai trouvé une solution à mon problème.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    if (fork() > 0) {
    		int n, state, nfds = 0;
    		fd_set r_fdset, w_fdset;
    		struct timeval dt = {5, 0};
     
    		/* Set pour le select */
    		FD_ZERO(&r_fdset);
    		FD_SET(pw[0], &r_fdset);
     
    		printf("Depart\n");
    		write(pr[1], "test", 5*sizeof(char));
     
    		/* Fermeture du pipe */
    		close(pr[1]);
     
    		state = select(pw[0]+1, &r_fdset, NULL, NULL, &dt);
     
    		if (state == -1) {
    			perror("select()");
    			return EXIT_FAILURE;
    		} else if (state > 0) {
    			if (FD_ISSET(pw[0], &r_fdset)) {
    				char c[10];
     
    				read(pw[0], c, 5*sizeof(char));
    				printf("Arrive %s\n", c);
    			}
    		} else {
    			printf("Timeout\n");
    			return EXIT_FAILURE;
    		}
     
     
    	} else { /* Executeur */		
    		char c[10];
    		int n;
     
    		n = read(pr[0], c, 5*sizeof(char));
    		printf("Choppe %s\n", c);
    		write(pw[1], c, 5*sizeof(char));
    	}
     
    	close(output_fd);
     
    	return EXIT_SUCCESS;
    Par contre je me demande ce qu'il se passerait si le retour du fils arrivait avant l'appel du select().

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. probleme de pipe + fork
    Par jerem721 dans le forum C
    Réponses: 0
    Dernier message: 12/02/2011, 22h48
  2. problème chat avec socket/fork/pipe
    Par cedricdd dans le forum Réseau
    Réponses: 10
    Dernier message: 08/03/2007, 14h56
  3. Fork et pipe
    Par Ylias dans le forum Shell et commandes GNU
    Réponses: 6
    Dernier message: 30/05/2006, 09h13
  4. Réponses: 1
    Dernier message: 07/04/2006, 13h35
  5. [PERL] Problème en essayant de comprendre fork et pipe
    Par LE NEINDRE dans le forum Langage
    Réponses: 6
    Dernier message: 04/10/2005, 15h23

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo