[Résolu] Lancement de plusieurs processus

Bonjour,

je suis débutant en programmation systeme, je sollicite votre aide pour m’aider à écrire le main de mon programme.
Pour l’écriture du programme, il faut uniquement que j’utilise des fork, pipe… car je n’ai pas vu les threads…

J’explique ce qu’il faut faire :

[quote]-avoir plusieurs traceroute s’effectuant simultanément, afin de rassembler des informations le plus vite possible
-pouvoir choisir à la volée combien de traceroute on souhaite exécuter en parallèle)
-ajouter de nouvelles « cibles » pour traceroute pendant que l’ensemble fonctionne.[/quote]
Les résultats des traceroute (avec l’option -n) lancés doivent être écrits dans un fichier pour pouvoir analyser les lignes et ainsi créer un graphe.

Le parsing et la création du graphe ont été faits, c’est le lancement des traceroutes et l’écriture dans le fichier qui pose problème.

Voici ce que j’ai écrit. Il n’est pas complet et aimerait que vous m’aidez pour faire en sorte qu’il le soit.

Merci par avance

[code]// structure pour gérer une info fils => père
typedef struct {
info1;
info2;
info3;
info4;
//…les infos qu’il faut
} t_info;

// structure pour gérer un fils et son pipe
typedef struct {
int cote[2]; // Cotés du pipe
int pid; // PID du fils
} t_fils;

int main(void)
{
t_fils tabFils[n]; // Tableau des fils
int i; // Boucle
int nbFils; // Nb fils vivants
t_info info; // Info transmise

// Création des processus
for (i=0; i < n; i++)
{
// Ouverture du pipe pour le fils vers son père
pipe(tabFils[i].cote);

  // Création du processus fils
  if ((tabFils[i].pid=fork()) == 0)
{
  // Ici on est dans le fils "i"
  
  // On commence par fermer le coté de lecture inutile
  close(tabFils[i].cote[0]);
  
  // Traceroute vers ip X
  //...
  
  // Récupération de toutes les IP situées entre moi et "x" => tableau d'IP
  //..
  
  //  Transmission de ce tableau vers le père par le pipe
  for (//...)
  {
    // Remplissage infos (une des info pourrait être le n° du fils)
    info.info1=i;
    info.info2=//...
      //... (on remplit toutes les infos)
      
      // On envoie l'info au père
      write(tabFils[i].cote[1], &info, sizeof(info);
        
     // on envoie une info particulière signifiant "fini"
     write(tabFils[i].cote[1], "EOT", 4);
        
    // Toutes les Ip sont transmises - Fin du fils (mais fermeture pipe avant)
    close(tabFils[i].cote[1]);
    exit(0);
  }
    
  // Ici on est dans le père - On n'a rien à faire sauf à fermer le coté d'écriture inutile
close(tabFils[i].cote[1]);
}

    // Ici, tous les fils sont lancés - On scrute maintenant les pipes tant qu'il y a des fils
    nbFils=n;
  while (nbFils > 0)
  {
    // On lit tous les pipes des fils
    for (i=0; i < n; i++)
      {
    // Si le fils "i" n'existe plus on le saute
    if (tabFils[i].pid == 0)
      continue;
    
    // Lecture du pipe venant du fils "i"
    if (read(tabFils[i].cote[0], &info,  sizeof(info)) > 0)
      {
        // Si on a reçu l'info particulière "EOT"
        if (//... == "EOT")
        {
          // On ferme le pipe de ce fils
          close(tabFils[i].cote[0]);
          
          // Le fils a terminé => pid mis à 0 (permettra de ne plus le traiter)
          tabFils[i].pid=0;
          
          // Un fils en moins
          nbFils--;
          
          // Inutile d'en faire plus pour ce crevard
          continue;
        }
        
        // Ici, on a reçu les infos sur les IP pour le fils "i"
        //... => on les analyse et on construit le graphe
     }
        
    // ici, soit on n'a rien reçu, soit on a fini de traiter les infos => on reboucle sur le fils suivant
        sleep(1);

}
}
// Ici, il n’y a plus de fils

}
[/code]

Pourrais tu décrire l’algo que tu as choisi autrement que par le commentaire dans des sources ?
Peux tu expliquer aussi tes choix de structures ?

[quote=“MattOTop”]Pourrais tu décrire l’algo que tu as choisi autrement que par le commentaire dans des sources ?
Peux tu expliquer aussi tes choix de structures ?[/quote]
Salut,

je n’ai écrit que ce que j’ai mis dans le 1er post. Je ne sais pas comment m’y prendre.

Je mets l’énoncé complet pour que vous puissiez m’aider.
Toutes les autres parties ont été faites exceptés le lancement des traceroute

Merci par avance

[quote]Le réseau Internet peut être grossièrement assimilé à un graphe, dont les noeuds sont les hôtes (machines, routeurs…) et les arêtes les liens entre ces hôtes. Depuis un noeud A donné, il est très difficile d’avoir une vue d’ensemble du réseau ; cependant, on peut effectuer un « traceroute » vers un autre noeud B, et dans la plupart des cas, obtenir une liste de noeuds formant un chemin entre A et B.

Sur Internet, une machine (ou un routeur, c’est pareil!) peut avoir 1 ou plusieurs adresses IP, et chaque adresse IP peut avoir 0, 1 ou plusieurs noms DNS rattachés. Inversement, un nom DNS peut être rattaché à 0, 1 ou plusieurs adresses IP. Comme les relations entre les adresses IP et les noms DNS sont complexes, on ignorera complètement les noms DNS. D’autre part, même si une machine peut avoir plusieurs adresses IP, on n’essaiera pas de « deviner » si plusieurs adresses appartiennent à la même machine ou pas. On raisonnera donc, finalement, en adresses IP plutôt qu’en machines ou routeurs ou noms DNS.

L’option -n de la commande traceroute permet de désactiver la résolution DNS (la conversion des adresses IP en noms)

~traceroute -n 192.48.96.9 traceroute to 192.48.96.9 (192.48.96.9), 30 hops max, 40 byte packets 1 192.168.0.1 9.754 ms 9.461 ms 8.046 ms 2 195.6.244.14 60.885 ms 48.924 ms 90.517 ms 3 194.206.126.244 50.503 ms 48.97 ms 120.122 ms 4 194.206.126.2 55.655 ms 52.213 ms 58.908 ms 5 208.213.229.130 588.303 ms 589.843 ms 589.611 ms 6 208.213.229.129 599.564 ms 599.763 ms 600.749 ms 7 208.213.229.226 629.167 ms 599.284 ms 599.383 ms 8 195.10.40.34 599.152 ms 599.289 ms 631.011 ms 9 157.130.34.217 642.326 ms 715.072 ms 653.724 ms 10 146.188.160.62 595.143 ms 590.433 ms 659.247 ms 11 146.188.160.181 649.863 ms 700.901 ms 617.067 ms 12 137.39.253.86 600.835 ms 599.379 ms 590.867 ms 13 192.48.96.9 607.071 ms 589.221 ms 603.156 ms
Attention, le graphe d’Internet n’est pas forcément un graphe « idéal », et les chemins que vous verrez apparaître en faisant des « traceroute » ne seront pas forcément les meilleurs ou les plus courts. Ne vous étonnez pas si par exemple, sur un traceroute, vous voyez des chemins non-optimaux !

D’autre part, ce n’est pas non plus un graphe figé ni déterministe, donc d’un jour à l’autre (ou même d’une minute à l’autre) un même traceroute pourra donner des résultats différents.

But du projet

Il s’agit d’écrire un programme (ou un ensemble de programmes) permettant d’effectuer des traceroute automatiquement, en tâche de fond ; et pendant que se font ces traceroute, de rassembler des informations sur le graphe d’Internet. En particulier, pour chaque noeud du graphe (on assimilera un noeud à son adresse IP), on souhaite pouvoir connaître ses voisins, ainsi que sa distance minimale à l’ « origine » (la distance n’est pas forcément constante, par exemple entre le noeud A et le noeud B, le noeud X peut apparaître en 5è position ; et le même noeud X peut apparaître en 8è position entre le noeud A et le noeud C – c’est surprenant, mais c’est possible!).

Il est indispensable de pouvoir :

* avoir plusieurs traceroute s’effectuant simultanément, afin de rassembler des informations le plus vite possible ;
* pouvoir choisir à la volée combien de traceroute on souhaite exécuter en parallèle) ;
* ajouter de nouvelles « cibles » pour traceroute pendant que l’ensemble fonctionne ;

* ajouter des cibles « aléatoires » (en tirant des adresses IP au hasard) ;
* visualiser des statistiques indiquant le nombre d’adresses IP « explorées » (nombre total, et classement par distance par rapport à l’origine) ;

  • indiquer les « voisins » d’un noeud donné par son adresse IP ;
  • exporter (et importer) l’état du graphe, sous forme de deux fichiers CSV : un contenant la liste des sommets (adresses IP) avec leur distance minimale à la source, et un autre contenant une liste de couples d’adresses IP ;

Informations techniques

Une adresse IP = 4 octets. Généralement on la représente sous la forme 134.157.0.129 (sous forme de 4 nombres entiers, en décimal, séparés par des points).
Les plages d’adresses suivantes sont « privées », c’est-à-dire internes :

* 10.0.0.0 à 10.255.255.255
* 172.16.0.0 à 172.31.255.255
* 192.168.0.0 à 192.168.255.255

La plage 224.0.0.0 à 239.255.255.255 est réservée au multicast.
Les adresses de 240.0.0.0 à 255.255.255.255 sont réservées.
Toutes ces plages (adresses privées, multicast, réservées) ne doivent pas être traitées

Le format CSV à utiliser, pour la liste des noeuds : adresse IP, distance
1.2.3.4,17
134.157.0.129,8
193.55.63.92,2
Le format CSV à utiliser, pour la liste des arêtes : adresse IP1, adresse IP2
1.2.3.4,1.2.3.5
134.157.0.129,134.157.254.1
193.55.63.1,193.55.63.29
On utilisera \n comme séparateur de lignes.[/quote]

Salut,

j’ai modifié le programme précédent
voici ce que j’ai fait mais il manque beaucoup de trucs comme le lancement des traceroutes avec l’option -n dont les résultats seront mis dans un fichier en vue d’être parsé.

Je rappelle, que j’ai codé toutes les parties excepées le lancement des traceroute

Si quelqu’un pouvait m’aider, svp pour avoir un code complet?

est-ce que quelqu’un pourrait m’indiquer à quel momment dans le code lancé les traceroute ainsi que le fait de mettre le résultat dans un fichier car je doit le parser pour créer le graphe.

la fonction de parsing à ce prototype char **Parsing(FILE *fichier) et la création du graphe CreerGraphe(char **tab)

Merci

[code]#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#define n 4
typedef int info;

// structure pour gérer une info fils => père
typedef struct {
info info1;
info info2;
info info3;
info info4;
//…les infos qu’il faut
} t_info;

// structure pour gérer un fils et son pipe
typedef struct {
int cote[2]; // Cotés du pipe
int pid; // PID du fils
} t_fils;

void traite_fils(t_info* info, t_fils* tuyau) {
for (int i=0; i < n; i++) {
// Traceroute vers ip X
//…

  // Récupération de toutes les IP situées entre moi et "x" => tableau d'IP
  //..
  
  //  Transmission de ce tableau vers le père par le pipe
  for (;;)//...)
  {
    // Remplissage infos (une des info pourrait être le n° du fils)
    info->info1=i;
    info->info2=//...
      //... (on remplit toutes les infos)
      
      // On envoie l'info au père
      write(tuyau->cote[1], info, sizeof(*info));
        
     // on envoie une info particulière signifiant "fini"
     write(tuyau->cote[1], "EOT", 4);
        
    // Toutes les Ip sont transmises - Fin du fils (mais fermeture pipe avant)
    close(tuyau->cote[1]);
    exit(0);
		}
}

}

int main()
{
t_fils tabFils[n]; // Tableau des fils
int i; // Boucle
int nbFils; // Nb fils vivants
t_info info; // Info transmise

// Création des processus
for (i=0; i < n; i++)
{
// Ouverture du pipe pour le fils vers son père
if (pipe(tabFils[i].cote) == -1) {
perror(“pipe”);
exit(EXIT_FAILURE);
}

  // Création du processus fils
  tabFils[i].pid = fork();
  switch (tabFils[i].pid)
{
    case -1:
        perror("fork");
        exit(EXIT_FAILURE);
    case 0:  // Ici on est dans le fils "i"  
        // On commence par fermer le coté de lecture inutile
        close(tabFils[i].cote[0]);
        traite_fils(&info,&tabFils[i]);
        break;
    default:
        // Ici on est dans le père - On n'a rien à faire sauf à fermer le coté d'écriture inutile    
        close(tabFils[i].cote[1]);
        break;
}

// on est sur d’etre dans le pere…

    // Ici, tous les fils sont lancés - On scrute maintenant les pipes tant qu'il y a des fils
    nbFils=n;
  while (nbFils > 0)
  {
    // On lit tous les pipes des fils
    for (i=0; i < n; i++)
      {
    // Si le fils "i" n'existe plus on le saute
    if (tabFils[i].pid == 0)
      continue;
    
    // Lecture du pipe venant du fils "i"
    if (read(tabFils[i].cote[0], &info,  sizeof(info)) > 0)
      {
        // Si on a reçu l'info particulière "EOT"
        if (true)//... == "EOT")
        {
          // On ferme le pipe de ce fils
          close(tabFils[i].cote[0]);
          
          // Le fils a terminé => pid mis à 0 (permettra de ne plus le traiter)
          tabFils[i].pid=0;
          
          // Un fils en moins
          nbFils--;
          
          // Inutile d'en faire plus pour ce crevard
          continue;
        }
        
        // Ici, on a reçu les infos sur les IP pour le fils "i"
        //... => on les analyse et on construit le graphe
     }
        
    // ici, soit on n'a rien reçu, soit on a fini de traiter les infos => on reboucle sur le fils suivant
     sleep(1);
	}
	}

// Ici, il n’y a plus de fils

}

}[/code]

Comme je te l’ai dit dans mon mail, tu abordes le problême en exploration, en pondant du code sans savoir ou tu va, et en reflechissant juste à “comment avancer un peu plus vers le resultat”. Ce n’est pas une manière efficace.
Déjà, il faut avoir une reflexion generale sur le problême, et voilà comment je m’y prendrais:
1 - La première chose à reflechir est la structure de ce que tu veux recupèrer. En reprenant le sujet:[quote]Le format CSV à utiliser, pour la liste des noeuds : adresse IP, distance
1.2.3.4,17
134.157.0.129,8
193.55.63.92,2
Le format CSV à utiliser, pour la liste des arêtes : adresse IP1, adresse IP2
1.2.3.4,1.2.3.5
134.157.0.129,134.157.254.1
193.55.63.1,193.55.63.29
On utilisera \n comme séparateur de lignes.[/quote]
Donc, il faut conserver en mêmoire ces deux types d’objets.

Partons du principe que pour la comparaison d’adresses adr1=adr2, il sera plus simple de manipuler des longint. Pareillement, le ttl d’un paquet etant limité, si je me souviens bien, à 256 hops, la mesure choisie etant le nombre de hops, il suffira d’un char pour stocker le nombre mini de hops pour atteindre un noeud.

On va devoir les balayer, ces objets, pour produire les CSV.
On doit considèrer qu’on travaille avec un nombre d’objets à priori illimités: ce qui est une bonne approximation pour l’IPV6, ne l’est pas forcément pour l’IPV4, mais ça nécessiterait de stocker 2^32 distance, et prendrait 4 Go de mêmoire.
Nous n’utiliserons donc pas de tableau.
On doit donc prevoir un chainage pour ça, on va utiliser des listes chainées (à priori dans un seul sens, tant qu’on a pas besoin de mieux).

Une structure de noeud serait alors simplement:typedef struct t_noeudIP { longint id; char minhop; struct t_noeudIP *next; };

Qu’est ce qu’une arète ? C’est juste une relation entre deux noeuds, point.typedef struct t_areteIP { (t_noeudIP *) t_areteIP[2]; // la syntaxe est peut être à corriger, ca fait longtemps que je n'ai pas fait de C struct t_areteIP *next; };

Cette structure est discutable: on va devoir faire des recherches dans la liste des noeuds, par exemple, pour savoir si il a déjà été visité, et comparer le nombre de hops. On va devoir aussi ressortir toutes les occurence d’arètes qui contiennent un noeud donné (quand on cherche les voisins). La liste chainée n’est pas idéale, et comme le cout mêmoire d’un tableau est prohibitif, la seule solution que je verrais serait d’utiliser un hachage pour accèlèrer le tout.
Mais AMA, ce n’est pas forcément l’objet du projet, donc restons avec une structure suffisante, même si elle n’est pas optimale.

2 - Maintenant, comment ça doit tourner ? Reprenons le texte:[quote]Il s’agit d’écrire un programme (ou un ensemble de programmes) permettant d’effectuer des traceroute automatiquement, en tâche de fond ; et pendant que se font ces traceroute, de rassembler des informations sur le graphe d’Internet. En particulier, pour chaque noeud du graphe (on assimilera un noeud à son adresse IP), on souhaite pouvoir connaître ses voisins, ainsi que sa distance minimale à l’ « origine » (la distance n’est pas forcément constante, par exemple entre le noeud A et le noeud B, le noeud X peut apparaître en 5è position ; et le même noeud X peut apparaître en 8è position entre le noeud A et le noeud C – c’est surprenant, mais c’est possible!).

Il est indispensable de pouvoir :

  • avoir plusieurs traceroute s’effectuant simultanément, afin de rassembler des informations le plus vite possible ;
  • pouvoir choisir à la volée combien de traceroute on souhaite exécuter en parallèle) ;
  • ajouter de nouvelles « cibles » pour traceroute pendant que l’ensemble fonctionne ;
  • ajouter des cibles « aléatoires » (en tirant des adresses IP au hasard) ;
  • visualiser des statistiques indiquant le nombre d’adresses IP « explorées » (nombre total, et classement par distance par rapport à l’origine) ;
  • indiquer les « voisins » d’un noeud donné par son adresse IP ;
  • exporter (et importer) l’état du graphe, sous forme de deux fichiers CSV : un contenant la liste des sommets (adresses IP) avec leur distance minimale à la source, et un autre contenant une liste de couples d’adresses IP ; [/quote]
    La première partie décrit vaguement l’algorythme de parcours de graphe à imaginer, et la série d’ “indispensables” te donne des éléments pour structurer l’interfaçage de ton projet.
    Prenons d’abord l’ “algorythmique” générale. Le texte demande de parcourir le voisinage en collectant des infos sur le nombre de hops minimale, et sur les voisinages detectés par les noeuds.
    Prenons maintenant cette question de la forme de ton appli.
  • Elle doit tourner en mode “démon”, et avec plusieurs actions en parallèles.
  • On doit pouvoir en cours d’execution:
    • passer le nombre d’actions max menées en //
    • ajouter des cibles à la volée (aléatoires ou choisies)
    • sortir des infos, à l’ecran, ou vers un fichier.

L’ideal pour faire ça aurait été que les processus lancés puissent partager leurs infos en mêmoire, mais puisque tu dois imperativement eviter les threads, on va passer par de la communication en pipe avec les fils.

Alors je vais être un peu moins verbeux que dans la première partie, parceque ça fait déjà quelques temps que je rediges, mais voilà comment je verrais ton appli:
un processus principal “demon” centralise la base de données des résultats acquis,
il lance toute une série de “travailleurs” qui effectuent le parcours de graphe, puis reste en ecoute de ses fils, pour mettre à jour la bdd ou leur fournir des infos de visite.
Comment discute t’il avec l’operateur ?
Je verrais bien que le trappage du signal USR1 provoque la lecture et l’execution d’un petit fichier de commandes à executer.

3 - Maintenant, l’algo à proprement parler:
un processus de parcours va prendre comme argument une adresse IP, et rendre juste le resultat du parsage, à savoir une liste de couples (adresse,nbhop). Idealement, pour accélèrer les choses, vu le temps pour determiner chaque hop pendant le traceroute, un fils devrait analyser le resultat du traceroute au fur et à mesure qu’il se fait, verifier auprés du controleur si le hop ou il est arrivé a été visité, et s’arrèter imediatement si c’est le cas.
Du coté du controleur, il gère une liste des noeuds à tracerouter. quand un fils rend la main, il fait l’ajout ou la mise à jour de minhop des nouveaux noeuds decouverts, les ajoute en queue de la liste des noeuds à tracerouter, et remet le noeud à l’origine du scan en queue de cette même file (pour le revisiter plus tard), puis il prends la premiere IP suivante dans la file et recommence.

Voilà. Bon, je vais faire à manger.

Salut, c’est partie la ou j’ai besoin d’aide, le reste a été fait.
J’ai écrit une fonction qui lit un fichier récupére les IPs et créer le graphe.
J’ai écrit les fonctions qui à partir du fichier CSV des voisins reconstruit l’arbre.
J’ai aussi créer la fonction permettant de donner une IP aléatoire

J’aurais aimer que tu m’écrives le code consacrer au lancement des processus car je n’en ai aucune idée et il me faut rendre le projet demain après-midi.

Si tu as besoin de voir ce que j’ai fait poour m’aider, je peux tout t’envoyer par mail.

Merci par avance

Dommage, mais là, je ne peux pas t’aider.
Pour tes pipes bloquants, essayes fgets

J’ai pas lu les posts précedents mais tu peux peut-etre t’en sortir avec des pipes bloquants:
-> man select
Il y a même un exemple, c’est rare!

Le select se met en attente sur tous tes pipes. Il va se debloquer dès que un des pipes recoit qqchose. A partir de ce moment là (ca depend de ton appli désolé j’ai pas le courage de tout lire), si tu veux que le serveur puisse encore recevoir des données sur les pipes il faut forker un fils qui va s’occuper du traitement de chaque client, comme ca tu reviens sur le select.
Attention select il faut lui passer n_fd+1