Previous Contents Next

4   Gestion de collisions

Pour bien comprendre la notion de gestion de collision, il vous est demandé de réaliser une couche de niveau liaison. Vous devrez gérer les collisions pouvant se produire lors de la communication de plusieurs PC sur un bus série. Si vous désirez aller jusqu'au bout de l'exercice, vous pourrez faire en sorte que le port série du PC se comporte comme une interface réseau Ethernet. Ainsi, il sera possible de tester l'efficacité de votre application en utilisant les utilitaires TCP/IP classiques (en particulier ping et ssh).

4.1   Dispositif matériel

Ce projet est basé sur un dispositif matériel qui implante un bus série. Ce dispositif ne comporte, comme composant électronique, que des diodes. Voici le schéma d'un dispositif à 4 ports :
Une réalisation de ce dispositif par Thierry Flamen de la plateforme électronique est visible sur ces deux photos. Vous y trouvez aussi le câble utilisé pour connecter le port série du PC au dispositif (câble avec un connecteur DB9 femelle et un connecteur RJ45 mâle).
 


4.2   Code fourni

Pour cette partie vous pouvez vous appuyer sur le code fourni dans l'archive http://www.plil.net/~rex/Enseignement/Reseau/Tutorat.Reseau.GIS3/linkCollisionsStudents.tgz. Il ne vous reste plus qu'a compléter les fichiers du sous-répertoire Programs. La génération des exécutables se fait par un simple make.

4.2.1   Bibliothèque série

Vous avez à votre disposition une bibliothèque permettant de gérer le port série. Cette bibliothéque ne comporte les fonctions décrites ci-après.
int serialOpen(char *device,int speed,int mode);
void serialClose(int fd);
La première fonction permet d'ouvrir le port série correspondant au périphérique device. Le port est configuré pour une vitesse de speed bauds. Il existe 3 modes d'ouverture :
SERIAL_READ
: possibilité de lire des octets sur le port série,
SERIAL_WRITE
: possibilité d'écrire des octets sur le port série,
SERIAL_BOTH
: possibilité de lire et d'écrire des octets sur le port série.
La seconde fonction ferme le port série. Dans le cadre du TP, le port série est représenté par le fichier spécial /dev/ttyS0 et il est conseillé de commencer par utiliser une vitesse faible (9600 bauds par exemple). Attention, par défaut vous n'avez pas accès au port série de votre PC de TP (affichez les permissions du fichier spécial). Pour obtenir l'accès au port série, utilisez la commande super serial.

4.2.2   Utilitaire de gestion d'interface Ethernet virtuelle

Pour ceux qui souhaitent aller plus loin il est possible de créer une interface Ethernet virtuelle. La création s'effectue avec la commande super addtap <@IP> <mask>, la destruction avec la commande super deltap. Une fois l'interface tap0 créée, il est possible de lancer l'utilitaire ethercat disponible dans le répertoire Utilities. Cet utilitaire utilise la bibliothèque du répertoire Ethernet pour se connecter sur l'interface Ethernet virtuelle. L'utilitaire ethercat affiche sur sa sortie standard les paquets reçus sur l'interface tap0 et envoi sur l'interface tap0 les paquets lus sur l'entrée standard. Les paquets lus sur l'entrée et affichés sur la sortie sont au même format : des octets en hexadécimal sur deux chiffres sans séparateur. Un paquet est terminé par un saut de ligne. L'utilitaire ethercat peut être utilisé, en conjonction avec les programmes d'envoi et de réception sur le port série, pour simuler une connexion Ethernet entre plusieurs machines.

4.3   Communication simple

Nous allons commencer par établir une communication entre deux PC via leurs ports série. Les deux ports série sont connectés par un bus série comme décrit en 4.1.

4.3.1   Procédure d'envoi sur le bus

Dans le fichier source serialWrite.c, écrivez un programme capable de lire des chaînes de caractères sur son entrée standard et de les envoyer sur le port série caractère par caractère. Attention le port série est ouvert en mode non bloquant. Ceci signifie qu'un appel à la primitive write peut échouer avec l'erreur EAGAIN pour cause de port série non immédiatemment prêt à envoyer un caractère. Dans ce cas, il convient d'attendre un cours instant avec la fonction usleep et de retenter l'envoi. N'oubliez pas de prévoir un mécanisme pour séparer les tableaux d'octets (chaînes de caractères). Vous pouvez par exemple transmettre les sauts de lignes. Si vous le souhaitez, vous pouvez aussi envoyer un caractère de début d'envoi.

4.3.2   Procédure de réception sur le bus

Dans le fichier source serialRead.c, écrivez un programme récupérant les octets sur le port série et affichant les tableaux d'octets sur la sortie standard. Attention, l'ouverture du port série en mode non bloquant influe aussi sur la lecture. Vous devez vérifier le retour de la primitive read, l'erreur de type EAGAIN ne doit conduire qu'à une attente courte suivie par une nouvelle tentative de lecture. Les octets ne doivent pas être affichés un par un mais stockés en mémoire et affichés uniquement sur réception de la marque de fin. Le programme doit aussi accepter des paramètres. Chaque paramètre est un préfixe permettant de filtrer les tableaux d'octets. Ne sont affichés que les tableaux commencant par l'un des préfixes. Ce filtrage permet, à terme, de ne laisser passer que les paquets dont l'adresse de destination concerne notre interface Ethernet virtuelle.

4.3.3   Premiers tests

Pour faire le premier test, connectez deux PC via un bus série. Lancez votre exécutable serialWrite sur un PC et votre exécutable serialRead sur l'autre PC. Tapez une chaîne de caractères sur l'entrée standard de serialWrite, elle devrait s'afficher sur la sortie standard de serialRead. Vous pouvez tester la gestion des préfixes en lançant serialRead avec des préfixes en paramètres et en vérifiant que les chaînes affichées sont bien celles commençant par ces préfixes.

Le second test vérifie le bon fonctionnement du bus série. Lancez aussi l'exécutable serialRead sur le premier PC. Vous devriez constater que les caractères envoyés par serialWrite arrivent sur tous les PC connectés au bus série. Essayez aussi avec un troisième PC.

Le troisième test consiste à lancer un serialRead sur un PC et deux serialWrite sur deux autres PC. Le but est d'effectuer un envoi simultané sur le bus série. Si vous avez du mal à synchroniser vos envois vous pouvez écrire une boucle d'affichage en shell et rediriger la sortie de cette boucle sur l'entrée de votre exécutable serialWrite. Que constatez-vous sur la sortie standard de votre exécutable serialRead ?

4.4   Somme de contrôle

Pour éviter d'afficher des tableaux d'octets corrompus, vous allez ajouter une somme de contrôle aux tableaux d'octets transmis sur le bus série.

4.4.1   Calcul de la somme de contrôle

Modifiez votre programme d'émission pour calculer une somme de contrôle et l'insérer en fin de tableau d'octets. Il vous est suggéré d'utiliser l'addition classique sur les octets et de tronquer la somme aux 16 bits de poids faibles. Pour insérer la somme de contrôle, vous pouvez, par exemple, utiliser la fonction sprintf avec un format du type "%04x".

4.4.2   Vérification de la somme de contrôle

Modifiez votre programme de réception pour vérifier la somme de contrôle une fois le paquet reçu. Pour lire la somme de contrôle vous pouvez utiliser la fonction sscanf avec le format "%x". Le paquet ne doit pas être affiché sur la sortie standard si la somme de contrôle n'est pas correcte.

4.4.3   Test de la somme de contrôle

Générez à nouveau des collisions avec des émissions simultanées. Vérifiez qu'aucun tableau d'octets n'est affiché. Arrêtez l'un des processus d'émission vérifiez que les tableaux d'octets sont affichés à nouveau.

4.5   Détection de collisions

Pour éviter les pertes de tableaux d'octets, vous allez mettre en place divers mécanismes déjà utilisé par le protocole Ethernet.

4.5.1   Ecoute de porteuse

Dans votre programme d'émission, ajoutez une fonction permettant d'attendre le silence sur le bus série avant d'envoyer un tableau d'octets. Il va donc falloir ouvrir le port série en lecture et écriture. Il faut aussi trouver un dispositif pour arrêter le programme de lecture sur le port série s'il est lancé sur la même machine. En effet si deux programmes lisent le port série en même temps, le résultat est indéterminé. Il vous est proposé de passer un paramètre optionnel à serialWrite pour lui communiquer le PID du serialRead. Avant l'envoi d'un tableau d'octets le processus serialWrite doit envoyer, en utilisant la primitive kill, un signal SIGSTOP au processus de PID passé en paramètre. Aprés l'envoi, qu'il y ait eu collision ou non, un signal SIGCONT doit être envoyé au même processus.

4.5.2   Détection de collision

Lors de l'envoi d'un tableau d'octets, vérifiez que les octets sont correctement envoyés. Pour cela, il faut faire autant de lectures que d'écritures en comparant les octets pour s'assurer qu'ils sont passés intacts. Si vous souhaitez avoir des performances correctes il ne faut pas essayer de vérifier chaque octet après l'avoir envoyé à cause de la latence entre émission et réception. Cela dit il ne faut non plus faire trop d'écritures avant les premières vérifications car cela conduit à une perte de bande passante en cas de collision. En cas de collision il faut arrêter l'émission immédiatement.

4.5.3   Retransmissions après collision

Lorsqu'une collision est détectée, une retransmission du tableau d'octets doit être retentée après une attente. Utilisez le même algorithme que pour Ethernet, à savoir 16 retransmissions avec des temps d'attentes tirés au hasard entre 0 et (2n)-1 unités où n est le numéro de la tentative. Réduisez l'intervalle à [0,1024] s'il est plus large. A vous de spécifier l'unité d'attente en fonction du temps nécessaire pour envoyer un petit tableau d'octets. N'oubliez pas de relancer l'éventuel processus serialRead avant l'attente. Utilisez la fonction usleep pour réaliser l'attente.

4.5.4   Test de détection de collisions

Générez à nouveau des collisions avec des émissions simultanées. Vérifiez que les tableaux s'affichent à nouveau, bien qu'éventuellement dans le désordre. Attention a ne pas saturer la bande passante avec des envois trop rapides.

4.6   Interface Ethernet virtuelle

Si vous souhaitez aller plus loin vous pouvez utiliser des interfaces Ethernet virtuelles pour tester votre couche liaison avec les utilitaires habituels comme ping et ssh. Regardez le script shell launch.sh qui vous montre comment combiner vos exécutables et l'utilitaire ethercat. Créez une interface Ethernet virtuelle par PC connecté au bus série en lui donnant une adresse IP d'un réseau IP commun (par exemple 192.168.0.0/24). Lancez ensuite le script launch.sh sur chaque PC. Enfin utilisez ping pour vérifier que votre couche liaison est capable de transporter des paquets IP. Vous pouvez aussi lancer des ping simultanés voire des ssh pour des tests exhaustifs.


Previous Contents Next