J'ai un mini projet à faire en c , et je bute sur les pipes.
Le prof nous a donné un code à compléter en 2 fichiers :
le fichier talk.c:
le fichier pmi.c :
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85 #include <stdio.h> /* Pour printf et fgets */ #include <unistd.h> /* Pour read, write et close*/ #include <stdlib.h> /* Pour exit */ #include <pthread.h> /* Pour les threads */ #include <string.h> /* Pour strcmp */ void talk(int in, int out, char* nom); /* Point d'entrée. * argv[1] : Nom de l'utilsateur. * argv[2] : Descripteur de lecture. * argv[3] : Descripteur d'écriture. */ int main(int argc, char **argv) { int in, out; /* Test du nombre d'aguments */ if (...) { //... /* Pause du processus pour que l'on ait le temps de lire le message d'erreur avant la fermeture de la fenetre */ sleep(3); exit(EXIT_FAILURE); } /* Conversion des DEUX parametres d'entrée en entiers */ in = atoi(argv[2]); //... /* Fonction principale de discussion */ talk(in, out, argv[1]); /* Fermeture du descripteur d'écriture */ //... return EXIT_SUCCESS; } /* * Thread de lecture. * inp est en fait un entier qui représenter le descripteur de lecture. */ void* lecture(void* inp) { int in = (int)inp; /* Lecture caractere par caractere en continu jusqu'a ce que une erreur survienne ou qu'une fin de fichier (EOF) soit lue : utiliser while et read (man 2 read) */ //... /* Affichage du caractère lu */ //... /* Fermer le descripteur de lecture */ //... } /* * Fonction principale de discussion: * in : descripteur de lecture * out : descripteur d'écriture * nom : nom de l'utilisateur */ void talk(int in, int out, char* nom) { pthread_t lect_th; /* Lancement du thread de lecture */ pthread_create(&lect_th, NULL, lecture, (void*)in); /* Boucle d'énvoi de messages */ do { /* Lecture d'une ligne */ fgets(...); /* Ajout du nom d'utilisateur au debut de la ligne */ sprintf(...); /* Envoi du message au correspondant */ write(...); /* On repete tant que la commande "/quit" n'a pas été tapée (utiliser strcmp) */ } while(...); }
Mon problème c'est que le programme talk marche bien tout seul si on met 1 et 2 en paramètre correspondant à stdin et stdout . Quand on écris ca renvoi sur la sortie standard. Mais sitôt que je le lance a partir des processus crées avec le programme pmi. Ce qui est écris ne s'affiche même plus ...
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 /* Pour printf et fgets */ #include <stdio.h> /* Pour strcmp */ #include <string.h> /* Pour fork, pipe et exec */ #include <unistd.h> /* Pour malloc, free, exit ... */ #include <stdlib.h> /* * Interpréteur de commandes, renvoie 1 si il faut quitter * l'application, 0 sinon. */ int interp_commande(char* ligne, char* mon_nom) { /* découpage de la ligne de commande en un tableau de mots */ // ... switch (commande) { case 'p': pid_t pid; /* Tester si il y a bien un nom en argument*/ //... /* pour parler il faut creer 2 processus, chacun devant executer une fenetre de dicussion */ /* Création du 1er processus fils*/ pid = fork(); if (pid < 0) { perror("fork"); } else if (!pid) { /* Code du premier processus fils */ int moi_vers_autre[2]; /* creation des DEUX tuyaux de communication (pipe) */ if (pipe(moi_vers_autre) < 0) { perror("pipe moi vers autre"); /* quitter */ return 1; } //... /* creation d'un 2eme processus */ //... if (pid) { /* 1er processus (fenetre 1 : autre) */ /* fermeture des DEUX extrémités du pipe non utilisées */ close(moi_vers_autre[1]); //... /* Ecriture des DEUX descripteurs des pipe dans des chaines */ sprintf(spfdin, "%d", moi_vers_autre[0]); //... } else { /* 2eme processus (fenetre 2 : moi) */ /* fermeture des DEUX extrémités du pipe non utilisées */ //... /* Ecriture des DEUX descripteurs des pipe dans des chaines */ //... } /* Retour dans les 2 processus fils (fenetres 1 et 2) */ /* Creation du titre de la fenetre de dicussion */ sprintf(...); /* Execution des 2 processus de discussion dans des terminaux graphiques. Utiliser le terminal 'xterm' avec l'option '-T' pour donner un titre a la fenetre et l'option '-e' pour donner la commande a executer */ execlp(...); /* Si exec() retourne c'est qu'il y a eu une erreur */ perror("exec"); } /* Retour dans le pere (PMI) */ break; case 'q': //... break; default: //... } /* Liberation de la mémoire occupée par le tableau d'arguments (args) */ /* Retourner en signalant que l'on ne quitte pas le processus */ //return ... } int main(int argc, char **argv) { int quit = 0; /* Faire un test de présence du nom d'utilisateur en argument */ // ... /* Boucle d'interprétation ds commandes */ while(!quit) { /* afficher un prompt */ //... /* Lecture d'une ligne */ //fgets(...) /* Suppression du retour chariot */ //... /* Interprétation de la ligne de commande */ quit = interp_commande(ligne, argv[1]); } }
Voila ce que j'ai fait :
pmi.c
talk.c
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 /* Pour printf et fgets */ #include <stdio.h> /* Pour strcmp */ #include <string.h> /* Pour fork, pipe et exec */ #include <unistd.h> /* Pour malloc, free, exit ... */ #include <stdlib.h> /* * Interpréteur de commandes, renvoie 1 si il faut quitter * l'application, 0 sinon. */ int interp_commande(char* ligne, char* mon_nom) { /* découpage de la ligne de commande en un tableau de mots */ char ** morceaux; morceaux = (char**)malloc(20*sizeof(char *)); char * morceau; int i=0; morceau = strtok(ligne," "); while(morceau != NULL){ morceaux[i] = morceau; morceau = strtok(NULL," "); i++; } char commande =morceaux[0][0]; pid_t pid; char spfdin[6]; char spfdout[6]; switch (commande) { case 'p': //Tester si il y a bien un nom en argument /* if(morceau[1] != NULL){ printf("Usage Commande parler: 'p' Nom "); return 0; }*/ /*pour parler il faut creer 2 processus, chacun devant executer une fenetre de dicussion*/ /*Création du 1er processus fils*/ pid = fork(); if (pid < 0) { perror("fork a rencontre un probleme"); return 1; } if (!pid) { //si pid == 0 alors c le processus fils /* Code du premier processus fils*/ int moi_vers_autre[2]; // descrpiteur de fichier int autre_vers_moi[2]; // creation des DEUX tuyaux de communication (pipe) if (pipe(moi_vers_autre) < 0) { perror("pipe moi vers autre"); // quitter return 1; } if(pipe(autre_vers_moi)<0){ perror("pipe autre vers moi"); return 1; } // creation d'un 2eme processus pid = fork(); // le processus fils a maintenant un fils aussi if (pid < 0) { perror("fork a rencontre un probleme"); return 1; } if(pid){ //1er processus (fenetre 1 : autre) // fermeture des DEUX extrémités du pipe non utilisées close(moi_vers_autre[1]); close(autre_vers_moi[0]);//... // Ecriture des DEUX descripteurs des pipes dans des chaines sprintf(spfdout, "%d", autre_vers_moi[1]); sprintf(spfdin, "%d", moi_vers_autre[0]); mon_nom = morceaux[1]; } else { // 2eme processus (fenetre 2 : moi) // fermeture des DEUX extrémités du pipe non utilisées close(moi_vers_autre[0]); close(autre_vers_moi[1]);//... // Ecriture des DEUX descripteurs des pipe dans des chaines sprintf(spfdin, "%d", autre_vers_moi[0]); sprintf(spfdout, "%d", moi_vers_autre[1]);//... } // Retour dans les 2 processus fils (fenetres 1 et 2) // Creation du titre de la fenetre de dicussion char titre [40]; //if(!pid) sprintf(titre,"Fenetre : %s (pid %d)",mon_nom,getpid()); //else sprintf(titre,"Fenetre : %s vers %s",morceaux[1],mon_nom); // Execution des 2 processus de discussion dans des terminaux /* graphiques. Utiliser le terminal 'xterm' avec l'option '-T' pour donner un titre a la fenetre et l'option '-e' pour donner la commande a executer */ printf("in: %s out: %s \n",spfdin,spfdout); execlp("xterm","xterm","-T",titre,"-e","./talk",mon_nom,spfdin,spfdout,NULL); // Si exec() retourne c'est qu'il y a eu une erreur perror("exec"); }/* Retour dans le pere (PMI)*/ break; case 'q': printf("Bye bye \n"); return 1; //break; inutile default: printf("Commandes disponible: 'p' pour parler 'q' pour quiter"); break;//... } // Liberation de la mémoire occupée par le tableau d'arguments (args) free(morceaux); // Retourner en signalant que l'on ne quitte pas le processus */ return 0; } int main(int argc, char **argv) { int quit = 0; char commande[80]; /* Faire un test de présence du nom d'utilisateur en argument */ if(argc != 2){ printf("Usage: Nom_utilisateur"); return -1; } printf("l utilisateur connecte est %s:", argv[1]); /* Boucle d'interprétation ds commandes */ while(!quit) { /* afficher un prompt */ printf("\n > "); /* Lecture d'une ligne */ fgets(commande, 80, stdin); /* Suppression du retour chariot */ int i=0; while(commande[i] != '\n'){ i++; } commande[i]='\0'; /* Interprétation de la ligne de commande */ quit = interp_commande(commande, argv[1]); } return 0; }
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 #include <stdio.h> /* Pour printf et fgets */ #include <unistd.h> /* Pour read, write et close*/ #include <stdlib.h> /* Pour exit */ #include <string.h> /* Pour strcmp */ #include <pthread.h> /* Pour les threads */ void talk(int in, int out, char* nom); /* Point d'entrée. * argv[1] : Nom de l'utilsateur. * argv[2] : Descripteur de lecture. * argv[3] : Descripteur d'écriture. */ int main(int argc, char **argv) { int in, out; /* Test du nombre d'aguments */ if (argc != 4) { printf("Usage : Nom_Utilisateur Descripteur_Lecture Descripteur_Ecriture \n"); /* Pause du processus pour que l'on ait le temps de lire le message d'erreur avant la fermeture de la fenetre */ sleep(3); exit(EXIT_FAILURE); } /* Conversion des DEUX parametres d'entrée en entiers */ //atoi(char *) deprecated in = (int)strtol(argv[2],NULL,10); out = (int)strtol(argv[3],NULL,10); /* Fonction principale de discussion */ talk(in, out, argv[1]); /* Fermeture du descripteur d'écriture */ close(out); return EXIT_SUCCESS; } /* * Thread de lecture. * inp est en fait un entier qui représenter le descripteur de lecture. */ void* lecture(void* inp) { int in = (int)inp; char c; /* Lecture caractere par caractere en continu jusqu'a ce que une erreur survienne ou qu'une fin de fichier (EOF) soit lue : utiliser while et read (man 2 read) */ while( read(in, &c, 1) > 0 ) /* Affichage du caractère lu */ putchar(c); /* Fermer le descripteur de lecture */ close(in); return inp; } /* * Fonction principale de discussion: * in : descripteur de lecture * out : descripteur d'écriture * nom : nom de l'utilisateur */ void talk(int in, int out, char* nom) { pthread_t lect_th; char message[256]; char ligne[300]; /* Lancement du thread de lecture */ pthread_create(&lect_th, NULL, lecture, (void*)in); /* Boucle d'envoi de messages */ do { /* Lecture d'une ligne */ fgets(message,256, stdin); /* Ajout du nom d'utilisateur au debut de la ligne */ sprintf(ligne,"%s %s",nom,message); printf("test: %s Le out correspond a : %d in: %d \n",message,out,in,stdin,stdout);//juste un test /* Envoi du message au correspondant */ write(out,ligne,strlen(ligne)); /* On repete tant que la commande "/quit" n'a pas été tapée (utiliser strcmp) */ } while(strcmp(message,"/quit\n")!=0); }
Partager