Académique Documents
Professionnel Documents
Culture Documents
TP Sockets : multi-chat
• Exercice 1 : L’objectif de cet exercice est de créer une application de multi-chat avec TCP. Le principe de fonctionnement est le
suivant : Un programme serveur joue le rôle de noeud central. Il reçoit toutes les demandes de connexions des clients qui participent
au chat. Chaque ligne écrite par un client est envoyé vers ce serveur. Celui-ci en fait une copie et retransmet le texte à tous les
autres clients. Le serveur doit donc être en mesure d’écouter sur une socket plusieurs demandes de connexions possibles. Parmi toutes
les connexions ouvertes, il doit aussi identifier la socket sur laquelle une écriture a eu lieu. La primitive accept étant bloquante son
utilisation ne permettrait pas à serveur d’écouter en même temps les écritures sur les sockets ouvertes. Une solution consiste à utiliser
la primitive select.
Complétez les lignes manquantes du programme serveur.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
addrlen = sizeof(clientaddr);
/* Ouverture de la socket du serveur */
if ((sock_cnx = socket(....)) == -1) {
perror("Erreur socket");
exit(1);
}
bzero(&serveraddr, sizeof(serveraddr));
serveraddr.sin_family = ....;
serveraddr.sin_port = ....;
serveraddr.sin_addr.s_addr = ....;
bzero(&(serveraddr.sin_zero), 8);
/* Bind */
if (bind(.......) == -1) {
perror("Erreur Bind");
exit(1);
}
/* Ecoute sur la socket, on autorise jusqu’a 10 requetes clients en attente */
if (listen(...) == -1) {
perror("Erreur Listen");
exit(1);
}
/* On initialize surveil_fds comme étant un ensemble vide */
FD_ZERO(....);
/* Positionne le bit associé à soc_cnx a 1 */
/* Grace à SELECT on pourra surveiller en ecoute soc_cnx sans à voir à utiliser la primitive bloquante accept */
FD_SET(sock_cnx, &surveil_fds);
fdmax = sock_cnx;
while (1)
Institut Galilée 15 avril 2013
{
read_fds = surveil_fds;
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("Erreur select");
exit(1);
}
/* Nous allons parcourir l’ensemble des descripteurs pour savoir qui a débloqué select */
for (i = 0; i <= fdmax; i++)
{
if (FD_ISSET(i, ....))
{
/* si le descripteur qui a debloqué select est soc_cnx */
/* alors on accepte l’ouvertur d’une connexion avec le nouveau client */
if (i == sock_cnx)
{
if ((newfd = accept(sock_cnx, (struct sockaddr *)&clientaddr, (int *)&addrlen)) == -1)
perror("Erreur accept");
else
{
/* On ajoute le nouveau descripteur dans l’ensemble des descripteurs */
FD_SET(......);
2. Complétez les lignes manquantes du programme client donné dans cet énoncé.
Institut Galilée 15 avril 2013
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/socket.h>
#include <signal.h>
if (argc != 4) {
fprintf(stderr,"usage: %s pseudo @IPserveur port\n",argv[0]);
exit(1);
}
id = argv[1];
sport = atoi(argv[3]);
serveur.sin_family = ....;
serveur.sin_port = ....;
inet_aton(argv[2],....);
bzero(&(serveur.sin_zero), 8);
socklen_t s = sizeof(serveur);
if (connect(...) < 0) {
fprintf(stderr,"%s: connect %s\n",argv[0],strerror(errno));
perror("bind");
exit(1);
}
len = sizeof(moi);
getsockname(....);
if ((pid = fork()) < 0) {
printf("erreur fork\n");
exit(-1);
}
else if (pid==0) for(;;) {
ret = read(...);
if (ret <= 0) {
printf("%s:erreur dans read (num=%d,mess=%s)\n", argv[0], ret, strerror(errno));
exit(2);
}
printf("%s\n",...);
}
else {
char message[200];
while (strcmp(message, "q") != 0) {
char buf_write[256];
fgets(message, 100, stdin);
if (message[strlen(message)-1] == ’\n’) message[strlen(message)-1] = 0;
Institut Galilée 15 avril 2013
3. Adaptez ce programme client pour avoir une version basée sur la primitive select permettant à un seul processus de surveiller
en parallèle l’entrée standard et la connexion avec le serveur de chat.