Partage
  • Partager sur Facebook
  • Partager sur Twitter

Faire communiquer deux process avec un named pipe

Comment faire ?

Sujet résolu
1 janvier 2016 à 15:00:35

Bonjour,

Je suis un grand débutant en C, et pourtant je suis censé coder deux programmes qui échangent des données l'un avec l'autre.
Et pour tout dire, je suis un peu perdu !
De fait, je viens quérir de l'aide ici. :D

Plus de détail sur ce que je cherche à accomplir :
Un premier programme/process qui envoie un message quelconque au second.
Un second prog/proc qui réceptionne ce message et l'affiche.
(Le projet est plus conséquent, mais si j'arrive déjà à faire ça, je devrais m'en sortir pour la suite.) 

A priori, après quelques (beaucoup en fait) recherches, il ressort que j'ai besoin d'utiliser un named pipe.
Pour le créer et l'utiliser, j'ai besoin de mkfifo, open, read and write.

J'ai donc les outils, mais pas doué comme je suis, je n'arrive pas à les utiliser. :euh: 

Du coup, voilà ma demande :
Est-ce que quelqu'un pourrait me montrer un exemple commenté pour faire ce fameux named pipe.

Et tant que j'y suis, bonne année à tous ! ^^

---

Edit : Déjà rien qu'avec ceci, je suis bloqué :

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

int main(void){
	const char* monTube = "essai.fifo";

	int mkfifo(monTube, 0644);
}

Le  compilateur me dit "expected ')' before numeric constant" pour le 0644...

en résumé : à l'aide ! :'(
 

-
Edité par mikamic 1 janvier 2016 à 22:25:45

  • Partager sur Facebook
  • Partager sur Twitter
Afin de ne pas alourdir inutilement ce topic, prenez la peine, avant toute question, de lire les deux dernières pages. Merci. :-)
1 janvier 2016 à 22:28:22

Et vu que l'ultimatum arrive à grand pas, je me permets un petit up... :magicien:
  • Partager sur Facebook
  • Partager sur Twitter
Afin de ne pas alourdir inutilement ce topic, prenez la peine, avant toute question, de lire les deux dernières pages. Merci. :-)
2 janvier 2016 à 0:09:57

Coucou,

fifo.h:

#ifndef INCLUDED_FIFO_H
#define INCLUDED_FIFO_H

#include <sys/types.h>

int
creatfifo(const char* path, int oflags, mode_t mode);

#endif

fifo.c:

#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <sys/stat.h>

#include "fifo.h"

int
creatfifo(const char* path, int oflags, mode_t mode)
{
    // path doit être non-nul.

    assert(path != NULL);

    // Si on ne réussi pas à créé un nouveau pipe nommé:

    if (mkfifo(path, mode) == -1)
    {
        // Si ce n'est pas parce que le fichier existe déjà, on retourne -1.

        if (errno != EEXIST)
        {
            return -1;
        }

        // Sinon on essaye de récupérer les informations le concernant.

        struct stat st;

        if (stat(path, &st) == -1)
        {
            return -1;
        }

        // Si ce n'est pas un pipe nommé on retourne -1.

        if (!S_ISFIFO(st.st_mode))
        {
            return -1;
        }
    }

    // Si la création a réussi, on ouvre le fichier et on retourne son fd.

    return open(path, oflags, mode);
}

master.c:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "fifo.h"

#define FIFO_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)
#define FIFO_PATH "hny.fifo"

int
main(void)
{
    int status = EXIT_SUCCESS,
        fifo = creatfifo(FIFO_PATH, O_WRONLY, FIFO_MODE);

    /*
    ** Si on a pas réussi à ouvrir notre pipe on gère et affiche la dernière
    ** erreur, on a status = erreur, et on va libérer les ressources acquises
    ** précédement par le programme (actuellement aucune, mais ça pourrait
    ** changer si on modifie le code).
    */

    if (fifo == -1)
    {
        perror("creatfifo");
        status = EXIT_FAILURE;
        goto fail_creatfifo;
    }

    for (unsigned int i = 0; i < 4096; ++i)
    {
        const char* s = "Happy new year !\n";

        /*
        ** On écrit notre message dans le pipe, en cas d'erreur, voir au
        ** dessus.
        */

        if (write(fifo, s, strlen(s)) == -1)
        {
            perror("write");
            status = EXIT_FAILURE;
            goto fail_write;
        }
    }

fail_write:

    // On ferme le pipe. En cas d'erreur, voir au dessus.

    if (close(fifo) == -1)
    {
        perror("close");
        status = EXIT_FAILURE;
        goto fail_close;
    }

fail_close:
fail_creatfifo:

    return status;
}

// Ceci n'est pas une pipe.

slave.c:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <unistd.h>

#include "fifo.h"

#define FIFO_MODE (S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)
#define FIFO_PATH "hny.fifo"

int
main(void)
{
    int status = EXIT_SUCCESS,
        fifo = creatfifo(FIFO_PATH, O_RDONLY, FIFO_MODE);

    /*
    ** On essaye d'ouvrir le pipe. Le serveur doit donc être lancé avant
    ** le client.
    */

    if (fifo == -1)
    {
        perror("creatfifo");
        status = EXIT_FAILURE;
        goto fail_creatfifo;
    }

    ssize_t n;
    char buf[BUFSIZ];

    /*
    ** On lit notre pipe jusqu'à ce qu'il y ait une erreur / EOF.
    */

    while ((n = read(fifo, buf, sizeof buf)) > 0)
    {
        // On écrit le message reçu sur la sortie standard.

        if (write(STDOUT_FILENO, buf, (size_t) n) == -1)
        {
            perror("write");
            status = EXIT_FAILURE;
            goto fail_write;
        }
    }

    if (n == -1)
    {
        perror("read");
        status = EXIT_FAILURE;
        goto fail_read;
    }

fail_read:
fail_write:

    // On ferme le pipe.

    if (close(fifo) == -1)
    {
        perror("close");
        status = EXIT_FAILURE;
        goto fail_close;
    }

fail_close:
fail_creatfifo:

    return status;
}

// Ceci n'est pas une pipe.
Pour ton erreur ce n'est pas lié aux pipes mais au langage en lui même, en C une assignation a cette forme:
// T est un type, x un identificateur et v une valeur

T x = v;

Au passage, les pipes nommés (s'ils sont bloquants) ne sont pas incompatibles avec les fonctions standard d'IO (printf, scanf, puts, …).

Le code donné est simplifiable, mais je l'ai écrit vite fait (:p) et il est assez simple à modifier et à comprendre, à mon avis.

EDIT: Correction, j'ai du mal à me remettre du nouvel an on dirait.

-
Edité par Mad scientist 2 janvier 2016 à 0:44:48

  • Partager sur Facebook
  • Partager sur Twitter
Un vrai cours de: (C | C++ | Haskell débutant | Haskell intermédiaire | Rust).
2 janvier 2016 à 13:41:40

Alors, tout d'abord, un grand merci ! :D 

Il m'a fallu un petit temps pour tout comprendre, mais ce fut fructueux...
Premier cas concret de création d'une librairie perso que je rencontre, et première fois que je tombe sur un goto.
J'ai trouvé la gestion d'erreur particulièrement élégante. (Je me voyais déjà m'amuser avec des if et des else imbriqué dans tous les sens... :p) 

Toutefois, quelques petites questions :
-Le EXIT_FAILURE et le EXIT_SUCCESS sont des constantes qui remplacent le 0 et le -1, c'est bien ça ?
-Le fifo.c définit le header fifo.h, exact ? Donc quand on inclue fifo.h, il va automatiquement cherche fifo.c sans qu'on ait besoin de lui signaler de le faire ?
-Concernant le fonctionnement du goto, c'est bien "goto nomDeLaBalise;" pour faire un bond jusqu'à la-dite balise ("nomDeLaBalise:") avec les ":" ?
-Que fait exactement la constante BUFSIZE (ligne 31 de slave) ?

El Psy Congroo ! ^^

  • Partager sur Facebook
  • Partager sur Twitter
Afin de ne pas alourdir inutilement ce topic, prenez la peine, avant toute question, de lire les deux dernières pages. Merci. :-)
2 janvier 2016 à 14:16:21

mikamic a écrit:

-Le EXIT_FAILURE et le EXIT_SUCCESS sont des constantes qui remplacent le 0 et le -1, c'est bien ça ?


EXIT_SUCCESS vaut bien 0, par contre la valeur de EXIT_FAILURE dépend de l'implémentation. Ces valeurs indiquent, dans le cas de EXIT_SUCCESS, que le programme s'est bien exécuté, et dans le cas de EXIT_FAILURE qu'il y a eu une erreur.

mikamic a écrit:

-Le fifo.c définit le header fifo.h, exact ? Donc quand on inclue fifo.h, il va automatiquement cherche fifo.c sans qu'on ait besoin de lui signaler de le faire ?

Pas exactement, fifo.h déclare les fonction définies dans fifo.c. Généralement chaque fichier *.c est compilé séparément, les headers permettent d'avoir les types des fonctions qu'on utilise (et d'autres trucs). Au moment du link les fichiers objets générés par les .c sont liés ensemble et ça te fait ton binaire final. Bien sûr c'est simplifié. ^^

mikamic a écrit:

-Concernant le fonctionnement du goto, c'est bien "goto nomDeLaBalise;" pour faire un bond jusqu'à la-dite balise ("nomDeLaBalise:") avec les ":" ?


Oui. En C son utilisation principale est la gestion d'erreur. Évite de l'utiliser en dehors de ce contexte, une utilisation abusive peut vite rendre ton code illisible.

mikamic a écrit:

-Que fait exactement la constante BUFSIZE (ligne 31 de slave) ?


BUFSIZ c'est la taille utilisé pour les buffers par défault des fonctions de <stdio.h>. C'est sensé être plus ou moins optimal et c'est assez explicite, donc je m'en sert assez souvent.

mikamic a écrit:

El Psy Congroo ! ^^

MOUAHAHAHAHA !!! Nous allons bientôt pouvoir mettre à exécution notre plan top secret de domination du monde !

EDIT: Dans slave.c, je dis à un moment que le serveur doit être ouvert avant le client, mais ce n'est plus vrai. En fait dans slave.c j'ouvrais le pipe avec un simple open, puis j'ai changé et créé la fonction creatfifo, mais je n'ai pas changé le commentaire.

-
Edité par Mad scientist 2 janvier 2016 à 14:30:47

  • Partager sur Facebook
  • Partager sur Twitter
Un vrai cours de: (C | C++ | Haskell débutant | Haskell intermédiaire | Rust).
2 janvier 2016 à 15:29:47

A priori, tout est clair, maintenant. Je pense que j'ai enfin acquis le Reading:Steiner ! :ninja:

Du coup, un tout grand merci. Puisse l'organisation ne pas ruiner vos projets, Okarin... Heu.. Hououin, je veux dire. :p

  • Partager sur Facebook
  • Partager sur Twitter
Afin de ne pas alourdir inutilement ce topic, prenez la peine, avant toute question, de lire les deux dernières pages. Merci. :-)
13 février 2024 à 11:04:04 - Message modéré pour le motif suivant : Merci de créer votre propre sujet


13 février 2024 à 12:42:21

@YoussoufSacko Bonjour, merci de ne pas squatter le sujet résolu des autres, créer votre propre sujet dans le respect des règles du forum à savoir qu'un message commence par des règles de politesses (Un bonjour ou des salutations à la communauté et se termine par des remerciements par avances pour les futures réponses), la description de votre problème et le code que vous avez écrit inséré sur le forum à l'aide de l'outil d'intégration de code soit le bouton code </>.

Déterrage

Citation des règles générales du forum :

Avant de poster un message, vérifiez la date du sujet dans lequel vous comptiez intervenir.

Si le dernier message sur le sujet date de plus de deux mois, mieux vaut ne pas répondre.
En effet, le déterrage d'un sujet nuit au bon fonctionnement du forum, et l'informatique pouvant grandement changer en quelques mois il n'est donc que rarement pertinent de déterrer un vieux sujet.

Au lieu de déterrer un sujet il est préférable :

  • soit de contacter directement le membre voulu par messagerie privée en cliquant sur son pseudonyme pour accéder à sa page profil, puis sur le lien "Ecrire un message"
  • soit de créer un nouveau sujet décrivant votre propre contexte
  • ne pas répondre à un déterrage et le signaler à la modération

Liens conseillés

Je ferme ici.

  • Partager sur Facebook
  • Partager sur Twitter