Communication inter-processus sous Linux

Principe de la communication entre processus

La communication inter-processus (IPC) désigne les mécanismes permettant à plusieurs processus d'échanger des données ou de partager des informations.

Objectifs de la communication

  • Échange de données
  • Partage de ressources
  • Synchronisation des processus
  • Transmission de messages

Fondement technique

Les processus communicants peuvent accéder à une zone mémoire commune.

Méthodes de communication inter-processus

Elles se répartissent en quatre catégories principales : tubes, IPC System V, IPC POSIX et sockets.

1. Tubes (Pipes)

Nom Description Caractéristiques
Tubes anonymes Communication entre processus apparentés Uniquement entre processus père/fils ou frères
Tubes nommés Communication entre processus quelconques Identifiés par un chemin dans le système de fichiers

2. IPC System V

Type Implémentation Fonction principale
Files de messages Espace de noms IPC Transmission basée sur des messages
Sémaphores Espace de noms IPC Synchronisation (ex. verrous d'exclusion mutuelle)
Mémoire partagée Espace de noms IPC + mapping mémoire Partage efficace de données via la mémoire

3. IPC POSIX

Type Implémentation Fonction principale
Files de messages Système de fichiers (identification par fichier) Transmission basée sur des messages
Sémaphores Système de fichiers (identification par fichier) Synchronisation entre processus
Mémoire partagée Fichier + mapping mémoire Partage efficace de données via la mémoire

4. Sockets

Nom Description Cas d'usage
Socket Voir progarmmation réseau Communication entre machines/distante

Tubes anonymes

Généralités

Utilisés pour la communication unidirectionnelle entre processus liés par parenté.

Propriétés

  • Communication semi-duplex
  • Flux d'octets, format défini par l'utilisateur
  • Principalement utilisé entre processus père et fils

Fonctionnement

Le processus parent invoque la fonction pipe() créant deux fichiers : un pour la lecture, un autre pour l'écriture. Ces fichiers utilisent un inode spécifique au tube. Les processus père et fils peuvent tous deux manipuler ce tube qui agit comme un tampon.

Communication bidirectionnelle : nécessite deux canaux distincts.
Restriction aux relations familiales : due aux différences dans les tables de fichiers.

Implémentation

// Valeurs de retour de fork()
// Enfant : 0 ; Parent : PID du fils ; Erreur : valeur négative

int pipe(int fd[2]);         // Crée un tube anonyme
int pipe2(int fd[2], int flags); // Version étendue avec options

// fd[0] : extrémité de lecture
// fd[1] : extrémité d'écriture

/* Flags possibles :
   O_NONBLOCK : mode non bloquant
   O_CLOEXEC  : fermeture lors d'appel execve */

// Fermeture d'une extrémité
int close(int fd);

// Lecture/écriture
ssize_t read(int fd, void *buffer, size_t taille);
ssize_t write(int fd, const void *data, size_t taille);

Exemple complet

#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>

#define MESSAGE "Bonjour depuis le tube !"

int canal[2];

void communiquer() {
    pid_t id_processus = fork();
    
    if (id_processus == 0) {
        close(canal[1]); // Ferme l'extrémité d'écriture côté enfant
        
        char reception[100];
        while(1) {
            memset(reception, 0, sizeof(reception));
            int octets_lus = read(canal[0], reception, sizeof(reception));
            
            if(octets_lus == 0) {
                printf("Enfant : Fin du tube détectée\n");
                break;
            }
            
            printf("Enfant : Lu %d octets : %s\n", octets_lus, reception);
        }
        
        close(canal[0]);
        _exit(0);
    } 
    else if (id_processus > 0) {
        close(canal[0]); // Ferme l'extrémité de lecture côté parent
    }
}

int main() {
    if(pipe(canal) == -1) {
        perror("Erreur création tube");
        return 1;
    }
    
    communiquer();
    
    for(int i = 0; i < 5; i++) {
        write(canal[1], MESSAGE, strlen(MESSAGE));
        sleep(1);
    }
    
    close(canal[1]);
    printf("Parent : Fin de transmission\n");
    return 0;
}

Tubes nommés (FIFO)

Concept

Un fichier spécial appelé FIFO permet la communication entre processus sans lien de parenté. Il est accessible via le système de fichiers.

Spécificités

  • Présent dans le système de fichiers, gérable comme tout autre fichier
  • Accessible par son nom plutôt que par un descripteur
  • Supporte la communication bidirectionnelle simultanée

Mécanisme

Un processus crée un FIFO avec mkfifo(), générant un inode particulier (similaire à celui des tubes anonymes). Plusieurs processus ouvrent ce même fichier via open(). Étant donné qu'ils pointent vers le même inode, ils peuvent communiquer ensemble.

Programmation

// Création d'un tube nommé
int mkfifo(const char *chemin, mode_t permissions);

// Paramètres :
// chemin     : emplacement du tube dans le système de fichiers
// permissions : droits d'accès Unix

// Retour :
// 0 en cas de succès, -1 sinon avec errno positionné

// Utilisation standard :
// open(), write(), read(), close()

Files de messages System V

Vue d'ensemble

Permet à plusieurs processus d'écrire et lire des messages simultanément. La priorité des messages permet de traiter certaines informations en priorité.

Architecture

Les processus appartenant au même espace de noms IPC peuvent accéder à la même zone mémoire.

// Génération d'une clé unique pour l'IPC System V
key_t ftok(const char *pathname, int projet_id);

// Obtention d'un identifiant de file de messages
int msgget(key_t cle, int options);

Étiquettes: Linux IPC processus pipes FIFO

Publié le 6 août à 06h40