TP réseau - Token ring en C - un paquet - mode connecté - multi messages

De Wiki de Romain RUDIGER
Aller à : navigation, rechercher

Retourner sur la page d'index concernant la conception de protocoles de communication Token ring en C++

Exercice 3 : Multiplexage en mode connecté

Rappel du cahier des charges

Problématique

Quelle est la meilleure façon de concevoir un protocole pour créer un anneau en mode connecté et permettant le multiplexage des messages.

Polytech S2 TP Reseau anneau.JPG

3.1.2 Description du paquet

Polytech S2 TP Reseau Description du paquet.JPG

3 messages peuvent être stockés dans le paquet, le principe est le même pour plus de messages. Il y a un contrôle des échanges puisque avant d’envoyer un message, il faut demander au destinataire s’il veut se connecter à l’émetteur puis l’émetteur envoie le message et se déconnecte s’il n’y a plus de message à envoyer. Voici la description du paquet que nous avons utilisé :

Pour chacun des trois slot (Sx) nous avons 4 champs :

  • Ex : ces champs définissent l’adresse de l’émetteur pour le slot x, c’est donc l’adresse de l’hôte qui a émis le paquet.
  • Dx : ces champs définissent l’adresse de destination pour chaque slot.
  • Fx : c’est le champ type, on a 6 types différents :
  1. demande de connexion
  2. acceptation de la connexion
  3. connecté
  4. accusé de réception
  5. déconnexion
  6. refus de la demande de connexion
  • Cx : chaque champ Cx contiendra les informations à transmettre.

Traitement logique du paquet

Nous avons fait un diagramme logique pour représenter le traitement logique qui est effectué lors de la réception d’un paquet :

Polytech S2 TP Diagramme Logique Paquet3.JPG

Polytech S2 TP Diagramme Logique Paquet31.JPG

Description de l’algorithme

Le diagramme logique ci dessous suffit largement pour écrire le programme, nous n’avons donc pas rédiger l’algorithme.

Code source du programme

/*
 * primitives.h
 * déclaration des variables et des fonctions
 *
 * Travaux Pratiques réseau SILR 1
 * ROCHE RUDIGER RAIRAT
 * 2006/07
 */

#include <sys/types.h> /* utilisé pour le type size_t 
			* permettant de connaitre la taille 
			* de la trame avant de l'envoyer */
#include <assert.h>  	/* pour insertion messages d'erreur */
#include <stdio.h>   	/* pour entree-sorties */
#include <stdlib.h> 		/* librairie */
#include <string.h>  	/* pour chaine de char */
#include <unistd.h> 		/* standard symbolic constants and types */
 
struct slot{ /* définition de la structure d'un slot */
    char adrs_emet[15]; /* adresse de l'émetteur */
    char adrs_dest[15]; /* adresse du destinataire */
    char type[3]; 		/* type : demande de connection(1), 
				* aceptation(2), refus(6), connecté(3), 
				* déconnecté(5), accusé(5) */
    char donnee[100]; 	/* Données */
};
typedef struct slot slot;

int nb_slot=3; //variable contenant le nombre de slot.
					//il faut le modifier sur tous les postes
					//ainsi que ci desous

struct trame{ //définition de la structure qui contiendra les slots
	 slot slot[3];
};
typedef struct trame trame;

char adrs_local[15];	//contiendra l'adresse de notre machine

char adrs_suiv[15];	//contiendra l'adresse de la machine suivante

int socketEmission, socketReception; //variable pour les sockets

int i;	//variable pour les boucles (for, while...)

int creePriseEmission (char *, int); //adresse, numéro de port

int creePriseReception (int); //numéro de port de réception

int recoit (int, trame *, size_t); //fonction permettant de recevoir une trame

int envoie (int, trame *, size_t); // fonction permettant d'envoyer une trame

void envoi_donnee (trame *, int);	/* fonction permettant d'envoyer des données
					 * ces données seront demandé à l'utilisateur
					* @param : adresse d'une variable de type trame */

Le programme est intitulé exo2 mais il correspond bien à l’exercice 3 :

/* exo2.c
 * fonction principale du programme
 *
 * Travaux Pratiques réseau SILR 1
 * ROCHE RUDIGER RAIRAT
 * 2006/07
 */

#include "primitives.h" /* fichier d'en tête des fonctions et declaration des variables */

/* fonction principale du protocol
 * @param : adresse IP de l'hote suivant
 * @param : port d'écoute de la machine suivante
 * @param : adresse IP locale
 * @param : port d'écoute de notre machine
 */
int main (int argc, char **argv)
{
    /*> test du nombre de paramètre */
   assert (argc == 5); /* erreur s'il n'y a pas 4 arguments */
    /* récupération des arguments et affichage */
   int port_emi; 	//contiendra le port d'émission
   int port_recep;	//contiendra le port de réception
   port_emi=atoi(argv[2]); 	//convertion de la chaîne de caractères en entier
   port_recep=atoi(argv[4]); 	//idem
   strcpy(adrs_local,argv[3]);	//copie de l'argument dans la variable
   strcpy(adrs_suiv,argv[1]);		//idem
	 /* affichage des arguments */
	printf("########################################\n");
   printf("#adresse du pc suivant : %s\n",adrs_suiv);
   printf("#port du pc suivant    : %d\n",port_emi);
   printf("#adresse de notre pc   : %s\n",adrs_local);
   printf("#port de reception     : %d\n",port_recep);
   printf("########################################\n");
	 /* initialisation des sockets */
   socketEmission = creePriseEmission (adrs_suiv, port_emi); /* socket pour l'émission vers le port passé en argument sur l'hote destination */
   socketReception = creePriseReception (port_recep); /* socket pour la reception sur le port passé en argument */
   trame t,*ptrame; /* création de la trame */
   ptrame=&t; /* création d'un pointeur sur cette trame */ 
    /* partie permettant d'envoyer une trame vide au poste suivant pour initialiser l'anneau */
	char reponse[2]; //contiendra la réponse de l'utilisateur
	printf("> Voulez vous initialiser l'anneau en envoyant une trame vide ? o/n ");
	scanf("%s",reponse);
	if(strcmp(reponse,"o")==0){
 		printf("########################################\n");
		printf("#Envoi d'une trame vide.\n");
		for(i=0;i<3;i++) strcpy(ptrame->slot[i].adrs_emet,""); //adrs emission a zéro pour les 3 slots
		envoie (socketEmission, ptrame, sizeof(trame)); //envoie
 		printf("########################################\n");
	}
	 /*> début de la boucle infinie */
   while(1){
			printf("########################################\n");
			printf("#Attente de la réception d'une trame...\n");
			recoit(socketReception, ptrame, sizeof(trame));
			traitement(ptrame);	//appel de la fonction traitant la trame
			printf("########################################\n");
   }
	return 0;
}
/* traiter.c
 * traitement d'un paquet
 *
 * Travaux Pratiques réseau SILR 1
 * ROCHE RUDIGER RAIRAT
 * 2006/07
 */

#include "primitives.h" /* fichier d'en tête des fonctions et declaration des variables */

/* fonction permettant d'afficher une trame 
 * @param : adresse d'une variable de type trame
 */
void afficher(trame *ptrame){
	for(i=0;i<nb_slot;i++){
		printf("#slot=%d\n",i);
		printf("#adrs_emet=%s\n",ptrame->slot[i].adrs_emet);
		printf("#adrs_dest=%s\n",ptrame->slot[i].adrs_dest);
		printf("#type=%s\n",ptrame->slot[i].type);
		printf("#donnee=%s\n",ptrame->slot[i].donnee);
	}
}

/* fonction permettant de modifier un slot pour y mettre des données
 * ces données seront demandé à l'utilisateur
 * @param : adresse d'une variable de type trame
 * @param : numéro du slot a modifier
 */
void envoi_donnee(trame *ptrame, int num_slot){
	strcpy(ptrame->slot[num_slot].type,"3");//code 3 : connecté
	strcpy(ptrame->slot[num_slot].adrs_dest,ptrame->slot[num_slot].adrs_emet);
	strcpy(ptrame->slot[num_slot].adrs_emet,adrs_local);
   printf("> Saisir les données (terminer la saisie par FIN : ");
	char saisie[30];
	strcpy(ptrame->slot[num_slot].donnee,"");
	do {
		scanf("%s",saisie);
		if(strcmp(saisie,"FIN")!=0){
		strcat(ptrame->slot[num_slot].donnee," ");
		strcat(ptrame->slot[num_slot].donnee,saisie);
		}
	} while(strcmp(saisie,"FIN")!=0);
	printf("#Envoi des données sur le slot %d.\n",num_slot);
}
/* fonction permettant de modifier un slot pour notifier un accusé de réception
 * @param : adresse de la trame reçu
 * @param : numéro du slot a modifier
 */
void envoi_accuse(trame *ptrame, int num_slot){
	printf("#Envoi de l'accusé sur le slot %d.\n",num_slot);
	strcpy(ptrame->slot[num_slot].type,"4");//code 4 : accusé de réception
	strcpy(ptrame->slot[num_slot].adrs_dest,ptrame->slot[num_slot].adrs_emet);
   strcpy(ptrame->slot[num_slot].adrs_emet,adrs_local);
}

/* fonction permettant de modifier un slot pour notifier une déconnection
 * @param : adresse de la trame reçu
 * @param : numéro du slot a modifier
 */
void envoi_deconnection(trame *ptrame, int num_slot){
	printf("#Envoi de la notification de déconnection sur le slot %d.\n",num_slot);
	strcpy(ptrame->slot[num_slot].type,"5");//code 4 : accusé de réception
	strcpy(ptrame->slot[num_slot].adrs_dest,ptrame->slot[num_slot].adrs_emet);
   strcpy(ptrame->slot[num_slot].adrs_emet,adrs_local);
}

/* fonction de traitement qui est appelée lors de la réception d'une trame
 * cette fonction agis en couche, elle fait des choix au fur et a mesure de la lecture du paquet.
 * @param : adresse d'une varaible de type trame
 */
int traitement(trame *ptrame){
	char reponse[2];//variable pour mémoriser la réponse de l'utilisateur
	//si une trame nous est destiné sur l'un des slots
	//afficher(ptrame);//affiche la trame que l'on vient de recevoir, pour le débuguage
	for(i=0;i<nb_slot;i++){//on analyse chaque slot de la trame
		if(strcmp(ptrame->slot[i].adrs_dest,adrs_local)==0){
			printf("#%s nous a envoyé quelque chose sur le slot %d.\n",ptrame->slot[i].adrs_emet,i);
			switch(atoi(ptrame->slot[i].type)){
				 case 1:{//c'est une demande de connection
					fflush(stdin);
					printf("> Aceptez vous la demande de connection ? o/n ");
					scanf("%s",reponse);
					if(strcmp(reponse,"o")==0){//ok on envoi une aceptation
						printf("#Vous avez acepté la connection.\n");
						strcpy(ptrame->slot[i].adrs_dest,ptrame->slot[i].adrs_emet);
						strcpy(ptrame->slot[i].adrs_emet,adrs_local);
						strcpy(ptrame->slot[i].type,"2");//code 2 : aceptation de la connection
						//envoi(socketEmission, ptrame, sizeof(trame));
					}
					else{//on envoi un refus
						printf("#Vous avez refusé la connection.\n");
						strcpy(ptrame->slot[i].adrs_dest,ptrame->slot[i].adrs_emet);
						strcpy(ptrame->slot[i].adrs_emet,adrs_local);
						strcpy(ptrame->slot[i].type,"6");//code 6 : refus de la connection
						//envoi(socketEmission, ptrame, sizeof(trame));
					}
					break;
				}
				case 2:{//c'est une aceptation de connection
					printf("#La connection a été acepté.\n");
					envoi_donnee(ptrame,i);
					break;
				}
				case 3:{//c'est un message
					printf("#C'est un message, le voici : %s\n",ptrame->slot[i].donnee);
					envoi_accuse(ptrame,i);
					break;
				}
				case 4:{//c'est un accusé de réception
					printf("#%s a bien reçu notre message.\n",ptrame->slot[i].adrs_emet);
					fflush(stdin);
					printf("> Voulez vous envoyer autre chose ? o/n ");
					scanf("%s",reponse);
					if(strcmp(reponse,"o")==0){//ok on envoi d'autre donnée
						envoi_donnee(ptrame,i);
					}
					else{//on se déconecte
						envoi_deconnection(ptrame,i);
					}
					break;
				}
				case 5:{//c'est une notification de déconnection
					printf("#%s s'est déconnecté.\n",ptrame->slot[i].adrs_emet);
					strcpy(ptrame->slot[i].adrs_emet,"");//on libère le slot
					break;
				}
				case 6:{//c'est une notification de refus de connection
					printf("#%s a refusé votre demande de connection :(\n",ptrame->slot[i].adrs_emet);
					strcpy(ptrame->slot[i].adrs_emet,"");//on libère le slot
					break;
				}
			}
		}
	}
	//maintenant on regarde si un slot est libre pour l'éventuelle envoi de donnee
	for(i=0;i<nb_slot;i++){//parcour des différents slots
		if(strcmp(ptrame->slot[i].adrs_emet,"")==0){//si un slot est libre
			fflush(stdin);
			printf("> Voulez vous envoyer un paquet ? o/n ");
			scanf("%s",reponse);
			if(strcmp(reponse,"o")==0){//on fait une demande de connection
				printf("> Entrez l'adresse de destination (d pour l'hote suivant) : ");
				scanf("%s",ptrame->slot[i].adrs_dest); 
				if(strcmp(ptrame->slot[i].adrs_dest,"d")==0) strcpy(ptrame->slot[i].adrs_dest,adrs_suiv);
				strcpy(ptrame->slot[i].adrs_emet,adrs_local);
				strcpy(ptrame->slot[i].type,"1");//code 1 : demande de connection
			}
		break;		
		}
	}
	envoie(socketEmission, ptrame, sizeof(trame));
	return 0;
}


Retourner sur la page d'index concernant la conception de protocoles de communication Token ring en C++