#include #include #include #include #include #include #include #include #include #include #include #include #include #include "client-serveur.h" #include "ajout-serveur.corrige.h" #define NBENFANTS 26 int pereEnfant[NBENFANTS][2]; int dernierNumVersionFichierLu = 0; /* Memoire partagee */ shm_t *shm; /* Semaphores */ int fifo; int mutexL; int mutexG; /* Procédures P et V pour manipulation du sémaphore #0 des objets sémaphores */ void P(int semId){ struct sembuf aBuf = {0, -1, 0}; int retour; retour = semop(semId, &aBuf, 1); assert(retour != -1); } void V(int semId){ struct sembuf aBuf = {0, +1, 0}; int retour; retour = semop(semId, &aBuf, 1); assert(retour != -1); } /* Procedure chargee de determiner ou, dans le fichier f, il y a des enregistrements qui correspondent a la lettre associée a monNum (si monNum == 0, 'A', 1 'B'...). Met a jour debutRech (1er enregistrement correspondant a la lettre) et finRech (dernier enregistrement correspondant a la lettre) en consequence */ void initDebutFin(FILE*f, int monNum, int *debutRech, int *finRech){ char ligne[256]; /* On cherche a partir d'ou il y a des enregistrements qui correspondent a */ /* la lettre associée a monNum (si monNum == 0, 'A', 1 'B'... */ rewind(f); while (feof(f) == 0) { *debutRech = ftell(f); if (fgets(ligne, sizeof(ligne), f) != NULL) { if ((ligne[0]-'A') == monNum) { break; } } } if (feof(f) == 0) { /* On a trouvé la lettre dans le fichier : on cherche le dernier endroit*/ /* où elle apparaît pour avoir finRech */ int dernFgetsOK; while (feof(f) == 0) { dernFgetsOK = ftell(f); if (fgets(ligne, sizeof(ligne), f) != NULL) { if ((ligne[0]-'A') != monNum) { *finRech = ftell(f); break; } } } if (feof(f) != 0){ *finRech = dernFgetsOK + strlen(ligne); } } else { /* On n'a pas trouvé la lettre dans le fichier : on positionne debutRech */ /* et finRech de la manière qui nous arrange le plus pour la suite */ *debutRech = 0; *finRech = 0; } } /* Traitement de requete */ void traiterRequete(requete_t *requete, FILE *f, int monNum){ reponse_t reponse; char ligne[256]; int fdW; int nbWrite; int debutRech; int finRech; /****************************************************************/ /* On se synchronise avec ajout (pour etre sur qu'on a le droit */ /* d'acceder au fichier) */ /****************************************************************/ P(fifo); P(mutexL); shm->nbLec += 1; if (shm->nbLec == 1) { P(mutexG); } V(mutexL); V(fifo); /**********************************************************************/ /* A partir d'ici, on est sur qu'ajout n'est pas en train de modifier */ /* le fichier : on peut maintenant traiter la requete */ /**********************************************************************/ /* On verifie que le fichier n'a pas change */ if (dernierNumVersionFichierLu != shm->numVersionFichier){ initDebutFin(f, monNum, &debutRech, &finRech); dernierNumVersionFichierLu = shm->numVersionFichier; } /* Calcul reponse->pointAccesPrive */ strcpy(reponse.pointAccesPrive, ""); /* Le point d'accès privé n'est pas utilisé dans cette appli */ /* Calcul reponse.contenu. */ if (fseek(f, debutRech, SEEK_SET) < 0) { perror("fseek"); exit(EXIT_FAILURE); } while ((feof(f) == 0) && (ftell(f) < finRech)) { if (fgets(ligne, sizeof(ligne), f) != NULL) { if (strncmp(ligne, requete->contenu, strlen(requete->contenu)) == 0){ break; } } } if ((feof(f) == 0) && (ftell(f) < finRech)) { strcpy(reponse.contenu, ligne); reponse.contenu[strlen(ligne)-1] = '\0'; /* Supprime le '\n' final */ } else { strcpy(reponse.contenu,"Désolé, je ne le connais pas"); } /* Affichage */ printf("L'enfant %d du serveur a recu \"%s\" et repond \"%s\"\n", getpid(), requete->contenu, reponse.contenu ); /* Connexion au point d'accès client et réponse */ fdW = open(requete->pointAccesClient, O_WRONLY); if (fdW == -1) { perror("open(pointAccessClient)"); exit(EXIT_FAILURE); } nbWrite = write(fdW, &reponse, sizeof(reponse)); if (nbWrite < sizeof(reponse)) { perror("pb ecriture sur pipe nomme"); } /* Dans cette application, le client ne renvoie pas de requête ultérieure*/ /* nécessitant une réponse ==> On peut fermer ce tube */ close(fdW); /*************************************************/ /* On signale la fin de traitement de la requete */ /*************************************************/ P(mutexL); shm->nbLec -= 1; if (shm->nbLec == 0) { V(mutexG); } V(mutexL); } void attenteRequete(int monNum){ requete_t requete; FILE *f; /* Ouverture du fichier de M. et Mme */ f = fopen("mEtMme.txt", "r"); if (f == NULL) { perror("open(mEtMme.txt)"); exit(EXIT_FAILURE); } /* Attente de requête */ while(1){ /* On attend une requête */ read(pereEnfant[monNum][0], &requete, sizeof(requete)); traiterRequete(&requete, f, monNum); } } int main() { requete_t requete; int fdR; int nbRead; int i; key_t key; int shmid; int retour; /******************/ /* Initialisation */ /******************/ /* Creation de la mémoire partagee */ key = ftok(NOMFIC,NOMPROJPOURSHM); assert( key != -1); shmid = shmget(key, sizeof(shm_t), 0600|IPC_CREAT); assert( shmid != -1); shm = (shm_t*) shmat(shmid, NULL, 0); assert(shm != (shm_t*)-1); /* Initialisation de la memoire partagee */ shm->nbLec = 0; shm->numVersionFichier = 1; /* Creation des semaphores */ key = ftok(NOMFIC,NOMPROJPOURFIFO); assert( key != -1); fifo = semget(key, 1, 0600|IPC_CREAT); assert(fifo != -1); key = ftok(NOMFIC,NOMPROJPOURMUTEXL); assert( key != -1); mutexL = semget(key, 1, 0600|IPC_CREAT); assert(mutexL != -1); key = ftok(NOMFIC,NOMPROJPOURMUTEXG); assert( key != -1); mutexG = semget(key, 1, 0600|IPC_CREAT); assert(mutexG != -1); /* Initialisation des differents semaphores */ retour = semctl(fifo, 0, SETVAL, 1); assert(retour != -1); retour = semctl(mutexL, 0, SETVAL, 1); assert(retour != -1); retour = semctl(mutexG, 0, SETVAL, 1); assert(retour != -1); /* Création du tube nommé du serveur */ if (mkfifo(NOMPOINTACCESSERV, S_IRUSR|S_IWUSR) < 0) { if (errno != EEXIST) { perror("mkfifo(tube nommé client"); exit(EXIT_FAILURE); } else { printf("%s existe deja : on suppose que c'est un pipe nomme\n", NOMPOINTACCESSERV ); printf("et qu'on peut continuer le programme sans probleme\n"); puts(""); } } /* Création du pool de fils */ /* Le pool est représenté par un tube sur lequel le père lit les */ /* numéros des fils qui se considèrent prêts à traiter des requêtes */ for (i=0 ; i='A') && (requete.contenu[0] <= 'Z')) { write(pereEnfant[requete.contenu[0]-'A'][1], &requete, sizeof(requete)); } else { /* On demande à l'enfant qui s'occupe des 'A' de répondre "Désolé" */ /* pour nous */ write(pereEnfant[0][1], &requete, sizeof(requete)); } }while(1); }