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

POSIX C Discussion :

communication bidirectionnels ?


Sujet :

POSIX C

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Points : 8
    Points
    8
    Par défaut communication bidirectionnels ?
    Bonjour à tous,

    Petite question sur les pipes bidirectionnels et sur ce coup, google n'a pas été mon ami. J'ai un programme qui fait un fork, mais j'aimerais que le père puisse écrire sur l'entrée standard du fils et récupérer ses sorties standard

    voici mon code:


    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/wait.h>
    #include <sys/types.h>
    #include <string.h>
    #include <errno.h>
     
    int main( int argc, char **argv )
    {
    	pid_t pid;
    	int pere_fils[ 2 ], fils_pere[ 2 ];
    	char s[ 100 ];
    	char f[ 100 ];
    	int status, i;
    	char **argument;
    	if (pipe( pere_fils ) == -1 || pipe( fils_pere ) == -1)
    	{
    		perror( "Erreur à la creation des pipes" );
    		return EXIT_FAILURE;
    	}
    	pid = fork();
    	if (pid == 0)
    	{
    		argument = (char **) malloc( argc * sizeof(char *) );
    		for (i = 0; i < argc - 1; ++i)
    			argument[ i ] = argv[ i + 1 ];
    		argument[ argc - 1 ] = NULL;
     
    		close( pere_fils[ 1 ] );
    		close( fils_pere[ 0 ] );
    		if (dup2( fils_pere[ 1 ], 1 ) == -1)
    		{
    			perror( "dup2" );
    			return 1;
    		}
    		close( fils_pere[ 1 ] );
     
    		if (dup2( pere_fils[ 0 ], STDIN_FILENO ) == -1)
    		{
    			perror( "dup2" );
    			return 1;
    		}
    		close( pere_fils[ 0 ] );
    		if (execvp( argv[ 1 ], argument ) == -1)
    		{
    			perror( "exec" );
    			return 1;
    		}
    	}
    	else if (pid != -1)
    	{
    		close( fils_pere[ 1 ] );
    		close( pere_fils[ 0 ] );
    		printf( ">params: " );
    		scanf( "%s", s );
    		write( pere_fils[ 1 ], s, strlen( s ) );
    		read( fils_pere[ 0 ], f, 100 );
    		printf( ">Resultat: %s\n", f );
     
    		wait( &status );
     
    	}
    	else
    	{
    		perror( "Erreur durant le fork" );
    		return EXIT_FAILURE;
    	}
    	return EXIT_SUCCESS;
    }
    avec ca aprés la compilation si je fait :
    je peut écrire mes mot mes je ne peut pas récupérer la resultat du "wc"

    une idée ?

  2. #2
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Il faut fermer le pipe dans le père, après le write, pour signaler la fin des données au fils. Tant que tu n'as pas fermé le pipe coté écrivain, le lecteur reste bloqué dans son read(). Quand l'écrivain ferme le pipe, le read() du lecteur retourne 0 (et fread() retourne EOF), signalant la fin du fichier.

    Tu as quelques autre problèmes mineurs dans ton programme :

    - Le scanf() ne lira que le premier mot entré. Pour ce que tu veux en faire, tu ferais mieux d'utiliser fgets().

    - Le printf() va t'afficher n'importe quoi, puisque les données lues du pipe ne sont pas terminées par un 0. Il faudrait que tu ajoutes un '\0' à la fin des données lues (à l'indice retourné par read()).

    Et par contre tu as deux gros problèmes qui passent tant que tu as peu de donnée, mais qui vont poser problème si tu as beaucoup de donnés (typiquement, plus de 4096 octets de données) :

    - Rien ne garanti que tu peux écrire la totalité des données en une fois, ou lire la totalité des données en un fois. Tu ne peux pas faire qu'un write() et qu'un read() ; il te faut une boucle de write() et une boucle de read().

    - Dans le cas général, les communications bidirectionnelles ne peuvent pas simplement se faire comme tu le fais, avec le père qui envoie l'intégralité des données, puis qui lit l'intégralité de la réponse. Ca va marcher (probablement, rien ne le garanti) avec "wc", mais si tu essaie avec "tr" par exemple, tu vas avoir un deadlock dès que tu va essayer d'envoyer une grande quantité de données. Le problème avec un process comme "tr", c'est qu'il écrit les données en sorti au fur et a mesure qu'il les lit en entrée. Au bout d'un moment le pipe de sortie va être plein, et le write() du file va bloquer. Du coup il ne lira plus le pipe d'entrée, qui va à son tour se remplir, et à ce moment le père va bloquer sur son write(). Tu te retrouve avec le père bloqué en attendant que le fils lise le pipe pere_fils, et le fils bloqué en attendant que le père lise le pipe fils_père. Pour régler le problème il faut que le père fasse une boucle avec un select() ou un poll() sur pere_fils[1] et fils_pere[0], pour traiter les données là où il y a des données à traiter (envoyer des données si pere_fils[1] est prêt, lire des données si fils_pere[0] est prêt).

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Points : 8
    Points
    8
    Par défaut
    Merci pour les suggestions,

    Citation Envoyé par matafan Voir le message
    Pour régler le problème il faut que le père fasse une boucle avec un select() ou un poll() sur pere_fils[1] et fils_pere[0], pour traiter les données là où il y a des données à traiter (envoyer des données si pere_fils[1] est prêt, lire des données si fils_pere[0] est prêt).
    j'ai réglé quelques problemes, mais je vois pas comment faire pour le poll()
    peut etre un bout de code me permet de bien saisir le mecanisme....


    Merci

  4. #4
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    16
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2005
    Messages : 16
    Points : 8
    Points
    8
    Par défaut
    une idée comment manipuler le poll() ?


    Merci

  5. #5
    Membre émérite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Octobre 2008
    Messages
    1 515
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Octobre 2008
    Messages : 1 515
    Points : 2 505
    Points
    2 505
    Par défaut
    Je te colles un morceau de code que j'ai sous la main qui fait ce genre de truc. Il utilises des fonctions et des structures de données externes, mais tu devrais pouvoir comprendre la logique quand mê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
    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
    /*    FUNCTION: interact
     * DESCRIPTION: Interact with a child process
     *   ARGUMENTS: - cmd: command associated with the child process
     *		- ifd: file descriptor connected to the child's stdin
     *		- ofd: file descriptor connected to the child's stdout
     *		- efd: file descriptor connected to the child's stderr
     *     RETURNS:
     *    MODIFIES: - cmd: out, outsz, err, errsz
     *    COMMENTS: ifd, ofd and efd are closed
     */
    static void
    interact(cmd_t *cmd, int ifd, int ofd, int efd)
    {
    	nfds_t nfds;
    	struct pollfd fds[3];
    	rdblock_t *oblock = NULL, *eblock = NULL;
    	char *in;
    	size_t olen = 0, elen = 0;
    	size_t insz;
     
    	/* Initialize poll list */
    	fds[0].fd     = ofd;
    	fds[0].events = POLLIN;
    	fds[1].fd     = efd;
    	fds[1].events = POLLIN;
    	if (cmd->insz != 0) {
    		/* Add ifd to poll list */
    		fds[2].fd     = ifd;
    		fds[2].events = POLLOUT;
    		nfds = 3;
    		/* Initialize current position in input buffer */
    		in   = cmd->in;
    		insz = cmd->insz;
    	} else {
    		close(ifd);
    		nfds = 2;
    	}
     
    	/* Poll file descriptors */
    	while (nfds > 0) {
    		int i;
     
    		poll(fds, nfds, -1);
     
    		/* See which fds are ready */
    		for (i = 0; i < nfds; i++) {
    			if (fds[i].revents) {
    				ssize_t rc;
     
    				if (fds[i].fd == ofd) {
    					/* Child's stdout has data */
    					rc = rdblock(ofd, &oblock, &olen);
    				} else if (fds[i].fd == efd) {
    					/* Child's stderr has data */
    					rc = rdblock(efd, &eblock, &elen);
    				} else {
    					/* Child's stdin accepts data */
    					rc = write(ifd, in, insz);
    					if (rc > 0) {
    						in   += rc;
    						insz -= rc;
    					}
    				}
     
    				if (rc <= 0) {
    					/* Error (rc == -1) or nothing more to
    					 * read/write (rc == 0). Either way,
    					 * close fd and remove it from poll
    					 * list.
    					 */
    					close(fds[i].fd);
    					nfds--;
    					if (i != nfds) {
    						fds[i].fd     = fds[nfds].fd;
    						fds[i].events = fds[nfds].events;
    					}
    				}
    			}
    		}
     
    	}
     
    	/* Save data read from child */
    	cmd->out = rdblock2data(oblock, olen);
    	cmd->outsz = olen;
    	cmd->err = rdblock2data(eblock, elen);
    	cmd->errsz = elen;
     
    }

Discussions similaires

  1. communication bidirectionnel entre le serveur et l'application
    Par Nono1nd dans le forum API standards et tierces
    Réponses: 11
    Dernier message: 11/03/2014, 04h43
  2. Communication bidirectionnelle entre 2 postes distants par Socket
    Par tails dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 05/07/2013, 16h42
  3. Réponses: 12
    Dernier message: 18/10/2012, 18h24
  4. communication corba
    Par joejoe dans le forum CORBA
    Réponses: 5
    Dernier message: 14/07/2002, 20h53
  5. communication entre programmes
    Par jérôme dans le forum C
    Réponses: 12
    Dernier message: 16/04/2002, 08h05

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