Previous Contents

A   Sources des scripts PHP

Deux sources sont disponibles : le source complet du pseudo-répéteur et le source des pseudo-stations à compléter.

A.1   Script du pseudo-répéteur

<?
/* Ce script simule un repeteur Ethernet sur lequel des machines vont
   se connecter pour echanger des paquets. 
   Un port d'ecoute permet la connexion des machines. Un autre port
   d'ecoute permet de recevoir une representation graphique du trafic
   affichable par un navigateur web.
   Les evenements simules sont la reception de donnees (des caracteres
   alphabetiques) et les collisions.
*/

/** Quelques constantes **/

define('PORT_AFFICHAGE','8000');
define('PORT_REPETEUR','4000');
define('TAILLE_FILE','16');

define('TEMPS_SYMBOLE','1.000');
define('PERIODE_AFFICHAGE',100.000+TEMPS_SYMBOLE/2);

define('SYMBOLE_DETECTION','?');
define('SYMBOLE_LIBRE','.');
define('SYMBOLE_COLLISION','*');
define('SYMBOLE_ERREUR','!');
define('NOM_COLLISION','collision');

define('TCP_NODELAY','1');

/** Fonctions **/

/* Cherche une socket donnee dans un tableau */

function socketPresenteDans($sock,$tableau){
foreach($tableau as $infos)
  if($infos['socket']==$sock) return TRUE;
return FALSE;
}

/* Supression d'une clef dans un tableau */

function supprimeClef($clef,&$tableau){
$nouveau=array();
foreach($tableau as $eltclef => $eltvaleur)  
  if($eltclef!=$clef) $nouveau[$eltclef]=$eltvaleur;
$tableau=$nouveau;
}

/* Retourne le schema des paquets a un navigateur */

function traiteNavigateur($sock,$paquets){
 /* Lecture de la requete du navigateur */
if(($buf=socket_read($sock,2048))===FALSE){
  echo "socket_read() failed: reason: ".socket_strerror ($ret)."\n";
  exit(1);
  }
$mots=explode(' ',$buf);
 /* Formate le tableau des paquets */
$schema=array();
$indice=count($paquets)-1;
if($indice>=0){
  $dernier=$paquets[$indice];
  $ddate=$dernier['date'];
  }
foreach($paquets as $paquet){
  $date=$paquet['date'];
  $nom=$paquet['nom'];
  $valeur=$paquet['valeur'];
  if($date>$ddate-PERIODE_AFFICHAGE){
    $rdate=$date-$ddate+PERIODE_AFFICHAGE;
    $indice=floor($rdate); $delta=$rdate-$indice;
    $liste=explode(',',$nom);
    foreach($liste as $n){
      $schema[$n][$indice]['valeur']=$valeur;
      $schema[$n][$indice]['delta']=$delta;
      }
    }
  }
 /* Code de reponse HTTP */
ob_start();
if($mots[0]!="GET"){
  echo "HTTP/1.0 501 Method Not Implemented\\nn";
  echo "<h1> Commande inconnue </h1>\n";
  }
else{
  echo "HTTP/1.0 200 OK\n";
  echo "Content-Type: text/html\n\n";
   /* Generation du schema de paquets */
  echo "<h1> Schéma temporel des derniers paquets </h1>\n";
  $origine=max(0,$ddate-PERIODE_AFFICHAGE);
  $entier=floor($origine);
  $ms=ceil(($origine-$entier)*1000);
  echo "L'origine des temps est le ".date('r',$entier)." et $ms ms<br><br>\n";
  echo "<table border=0>\n";
  foreach($schema as $nom => $ligne){
    echo "<tr><td>$nom</td>";
    $col=0;
    foreach($ligne as $position => $infos){
      $valeur=$infos['valeur'];
      $delta=$infos['delta'];
      for($i=$col;$i<$position-1;$i++) echo "<td>&nbsp;</td>";
      if($valeur==SYMBOLE_COLLISION) $couleur='red';
      else $couleur='blue';
      $texte="<span title=$delta>$valeur</span>";
      echo "<td bgcolor=$couleur><font color=white>$texte</font></td>";
      $col=$position;
      }
    echo "</tr>\n";
    }
  echo "</table>\n";
  }
$result=ob_get_contents();
ob_end_clean();
 /* Envoi du schema au navigateur */
socket_write($sock,$result,strlen($result));
socket_shutdown($sock,2);
}

/* Traite l'envoi d'un caractere par une station */

function getmicrotime(){ 
list($usec, $sec) = explode(" ",microtime()); 
return ((float)$usec + (float)$sec); 
} 

function traiteStation($sock,&$paquets){
 /* Lit les donnees envoyees par la station */
if(socket_recvfrom($sock,$buf,2048,0,$adresse,$port)<=0){
  echo "socket_recvfrom() failed: reason: ".socket_strerror ($ret)."\n";
  exit(1);
  }
list($donnee,$date)=explode(' ',$buf);
 /* Recuperation d'informations sur la station */
$nom="$adresse:$port";
 /* Cas de figure de la requete sur l'etat du medium */
if(strlen($donnee)>1) $donnee=SYMBOLE_ERREUR;
if($donnee==SYMBOLE_DETECTION){
  $copie=$paquets;
  $candidat=FALSE;
  while(TRUE){
    $dernier=array_pop($copie);
    $ddate=$dernier['date'];
    $dnom=$dernier['nom'];
    if($ddate<$date-2*TEMPS_SYMBOLE) break;
    if($ddate<=$date-TEMPS_SYMBOLE && $dnom!=$nom) $candidat=$dernier;
    }
  if($candidat===FALSE) $valeur=SYMBOLE_LIBRE;
  else $valeur=$candidat['valeur'];
  socket_sendto($sock,$valeur,strlen($valeur),0,$adresse,$port);
  return;
  }
 /* Verification de collision */
if(count($paquets)>0){
  $indice=count($paquets)-1;
  $dernier=$paquets[$indice];
  $ddate=$dernier['date'];
  $diff=$date-$ddate;
  if($diff<TEMPS_SYMBOLE){
    $paquets[$indice]['nom'] .= ",$nom"; 
    $paquets[$indice]['valeur']=SYMBOLE_COLLISION; 
    return;
    }
  }
 /* Memorisation du message de la station */
$paquets[]=array(
  'date' => $date, 'nom' => $nom, 'valeur' => $donnee
  );
}

/* Preparation des sockets d'ecoute */

function initialisationServeur($port){
if(($sock=socket_create(AF_INET,SOCK_STREAM,0))<0){
    echo "socket_create() failed: reason: ".socket_strerror($sock)."\n";
    exit(1);
    }
socket_set_option($sock,SOL_SOCKET,SO_REUSEADDR,1);
if(($ret=socket_bind($sock,"0.0.0.0",$port))<0){
    echo "socket_bind() failed: reason: ".socket_strerror($ret)."\n";
    exit(1);
    }
if(($ret=socket_listen($sock,TAILLE_FILE))<0){
    echo "socket_listen() failed: reason: ".socket_strerror($ret)."\n";
    exit(1);
    }
return $sock;
}

function initialisationServeurUDP($port){
if(($sock=socket_create(AF_INET,SOCK_DGRAM,0))<0){
    echo "socket_create() failed: reason: ".socket_strerror($sock)."\n";
    exit(1);
    }
if(($ret=socket_bind($sock,"0.0.0.0",$port))<0){
    echo "socket_bind() failed: reason: ".socket_strerror($ret)."\n";
    exit(1);
    }
return $sock;
}

function prepareSockets(){
$saff=initialisationServeur(PORT_AFFICHAGE);
$srep=initialisationServeurUDP(PORT_REPETEUR);
return array($saff,$srep);
}

/* Ecoute les sockets actives */

function socketDialogue($sock,&$tableau){
if(($dialogue=socket_accept($sock))<0){
  echo "socket_accept() failed: reason: ".socket_strerror($dialogue)."\n";
  exit(1);
  }
if((socket_getpeername($dialogue,$adresse,$port))===FALSE){
  echo "socket_getpeername() failed: reason: ".socket_strerror($dialogue)."\n";
  exit(1);
  }
$result=array( 'socket' => $dialogue, 'adresse' => $adresse, 'port' => $port );
return $result;
}

function ecouteSockets($ports){
$paquets=array();
list($saff,$srep)=$ports;
while(TRUE){
  $read=$ports;
  if(($num=socket_select($read,$write=NULL,$except=NULL,0))!==FALSE && $num>0)
    foreach($read as $sock){
      if($sock==$saff) {
        $dialogue=socketDialogue($sock,$navigateurs);
        traiteNavigateur($dialogue['socket'],$paquets);
 }
      else if($sock==$srep) traiteStation($sock,$paquets);
      else{ echo "ecouteSockets() assert failed: bad socket\n"; exit(1); }
      }
  }
}

/* Programme principal */

 /* script sans limite de temps */
set_time_limit(0);

 /* pas de tampon en sortie */
ob_implicit_flush();

 /* creation des sockets */
$sockets=prepareSockets();

 /* gestion des sockets */
ecouteSockets($sockets);
?>

A.2   Script des pseudos-stations

<?
/* Ce script simule une carte Ethernet qui est connectee sur un materiel
   de type repeteur.
*/

/** Quelques constantes **/

define('PORT_REPETEUR','4000');
define('TAILLE_FILE','16');

define('TEMPS_SYMBOLE','1.000');
define('TAILLE_TRAME_MIN','5');

define('SYMBOLE_DETECTION','?');
define('SYMBOLE_LIBRE','.');
define('SYMBOLE_COLLISION','*');

/** La structure contenant les messages à envoyer **/

/* L'exemple montre un message "constituant" a envoyer au top 10 */
/* Ce message est une diffusion (destination 99) envoyé de la    */
/* station d'adresse 01.                                         */

$messages=array(
   0 => array( 'top' => 10,
               'message' => '=9901consistant',
               'tentative' => 0,
               'pointeur' => 0 )
   ); 

/** Fonctions **/

/* Connexion au repeteur */

function connexionServeur($adresse,$port){
if(($sock=socket_create(AF_INET,SOCK_DGRAM,0))<0){
    echo "socket_create() failed: reason: ".socket_strerror($sock)."\n";
    exit(1);
    }
if(($ret=socket_connect($sock,$adresse,$port))<0){
    echo "socket_connect() failed: reason: ".socket_strerror($ret)."\n";
    exit(1);
    }
return $sock;
}

/* Retourne l'estampille de temps en microsecondes */

function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}

/* Attente du top suivant */

function attendreTop($top,$debut){
$datefin=$debut+TEMPS_SYMBOLE*$top;
$delai=$datefin-getmicrotime();
if($delai>0) usleep(1000000*$delai); 
return $datefin;
}

/* Recupere l'etat du medium reseau */

function etatMedium($dialogue,$date){
$message=SYMBOLE_DETECTION." $date";
socket_send($dialogue,$message,strlen($message),0);
socket_recv($dialogue,$reponse,2048,0);
return $reponse;
}

/* Envoi un symbole au repeteur */

function envoyerSymbole($dialogue,$symbole,$date){
$message="$symbole $date";
socket_send($dialogue,$message,strlen($message),0);
}

/* Simulation de la carte Ethernet */

function simulationEthernet($dialogue){
global $messages;
$top=0;
$debut=getmicrotime();
$date=$debut;
while(TRUE){
   /* Comportement suivant l'etat du medium */
  $etat=etatMedium($dialogue,$date);
  switch($etat){
    case SYMBOLE_LIBRE:  /* le medium est libre */
      /* Completer */
      break;
    case SYMBOLE_COLLISION: /* collision detectee */
      /* Completer */
      break;
    default:   /* message recu */
      /* Completer */
      break;
    }
   /* Passage au top d'horloge suivant */  
  $top++;
  $date=attendreTop($top,$debut);
  }
}

/* Programme principal */

 /* script sans limite de temps */
set_time_limit(0);

 /* pas de tampon en sortie */
ob_implicit_flush();

 /* connexion au serveur */
$dialogue=connexionServeur('127.0.0.1',PORT_REPETEUR);

 /* simulation de la carte */
simulationEthernet($dialogue);

?>

Previous Contents