/*********************************************************** serv_fork.c - UTILISER la commande netstat pour voir les connexions entrantes et sortantes sur la machine. - ATTENTION : le signal SIGCHLD n'est pas gere, il y aura donc plein de petits zombies a observer ! *********************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include /* SERVEUR */ int Sock_Serv, Sock_Com, Ret_Read, Taille; char Buf[1024]; static char MESSAGE[] = "Ici le process XXXXX fils de XXXXX...............\n"; struct sockaddr distant; int distant_len = sizeof distant; void Gerant_Comm (void); void Gerant_SIGCHLD (int); int main (int argc, char **argv) { struct sockaddr_in6 Le_Serveur; struct sigaction act; if (argc != 2) { fprintf (stderr, "Syntaxe : %s \n", argv[0]); return -1; } /* Récupération du signal SIGCHLD indiquant la terminaison d'un processus fils. */ act.sa_handler = Gerant_SIGCHLD; sigemptyset (&act.sa_mask); act.sa_flags = SA_RESTART; sigaction (SIGCHLD, &act, NULL); /* Création de la socket d'écoute */ if ((Sock_Serv = socket (PF_INET6, SOCK_STREAM, 0)) < 0) { perror ("Ouverture du socket en mode connecte\n"); exit (1); } /* Attachement de la socket d'écoute à une adresse sur le serveur */ Le_Serveur.sin6_family = AF_INET6; memcpy ((void *)&Le_Serveur.sin6_addr, (void*)&in6addr_any, sizeof in6addr_any); Le_Serveur.sin6_port = htons (atoi (argv[1])); Taille = sizeof (Le_Serveur); if (bind (Sock_Serv, (struct sockaddr *) &Le_Serveur, Taille) < 0) { perror ("Serveur : erreur sur bind "); exit (1); } /* Message de bienvenue. */ printf ("[%05d] Serveur en écoute sur le port %d.\n", (int) getpid (), ntohs (Le_Serveur.sin6_port)); /* * Le serveur se met en attente sur la socket d'écoute */ listen (Sock_Serv, 5); while (1) /* * cf. man -s 3n accept */ { if ((Sock_Com = accept (Sock_Serv, &distant, &distant_len)) == -1) { fprintf (stderr, "[%05d] ", (int) getpid ()); perror ("Erreur sur accept."); continue; } /* * Un client a demandé une connexion, Sock_Com contient * le numéro de la socket attribuée à cette connexion. * Nous créons un processus fils pour la gérer. */ if (/* fork () */ 0 == 0) { /* Le fils n'a plus besoin de la socket initiale. */ /* close (Sock_Serv); */ /* Gestion de la communication. */ Gerant_Comm (); /* Fin de connexion. */ exit (0); } else { /* Le serveur n'a pas besoin de la socket de communication. */ close (Sock_Com); } } return 0; } /**************** Fonction de gestion des communications ************/ void Gerant_Comm () { char *peer; char peeraddr[64]; struct hostent *peer_hent; char host[64], serv[64]; /* Récupérer l'identité du client. */ /* if (getpeername (Sock_Com, &distant, &distant_len)) */ if (0) peer = ""; else { if (distant.sa_family == AF_INET) peer_hent = gethostbyaddr ((char *) &(((struct sockaddr_in *)&distant)->sin_addr), sizeof ((struct sockaddr_in *)&distant)->sin_addr, AF_INET); else if (distant.sa_family == AF_INET6) { struct sockaddr_in6 *dist6 = (struct sockaddr_in6 *) &distant; printf ("[%05d] Recherche du hostname d'un client IPv6.\n", (int) getpid ()); getnameinfo (&distant, distant_len, host, sizeof host, serv, sizeof serv, NI_NUMERICHOST | NI_NUMERICSERV); peer_hent = gethostbyaddr ((char *) &(dist6->sin6_addr), sizeof dist6->sin6_addr, AF_INET6); } else printf ("[%05d] Connexion d'un client de famille inconnue %d.\n", (int) getpid (), (int) distant.sa_family); if (!peer_hent) { if (distant.sa_family == AF_INET) { struct sockaddr_in *distant_ipv4 = (struct sockaddr_in *) &distant; peer = inet_ntoa (distant_ipv4->sin_addr); } else { struct sockaddr_in6 *distant_ipv6 = (struct sockaddr_in6 *) &distant; inet_ntop (AF_INET6, &(distant_ipv6->sin6_addr), peeraddr, sizeof peeraddr); peer = peeraddr; } } else { peer = strdup (peer_hent->h_name); } } printf ("[%05d] Connexion de %s en IPv%c.\n", (int) getpid (), peer, (distant.sa_family == AF_INET) ? '4' : '6'); /* Envoi du message de bienvenue. */ if (write (Sock_Com, "Bonjour !\n", 10) < 0) { fprintf (stderr, "[%05d] ", (int) getpid ()); perror ("Erreur écriture message"); } do { memset (Buf, 0, sizeof (Buf)); printf ("[%05d] Attente d'un message du client.\n", (int) getpid ()); /* Réception d'un message du client */ if ((Ret_Read = read (Sock_Com, Buf, sizeof (Buf))) < 0) { fprintf (stderr, "[%05d] ", (int) getpid ()); perror ("Erreur lecture message"); continue; } if (Ret_Read == 0) { printf ("[%05d] Le processus fils a terminé.\n", (int) getpid ()); } else { Buf [Ret_Read] = '\0'; printf ("[%05d] Message reçu de %s:\n", (int) getpid (), peer); printf (" %s", Buf); } } while (Ret_Read > 0); sprintf (MESSAGE + 15, "%d fils de %d : reçu !\n", (int) getpid (), (int) getppid ()); if (write (Sock_Com, MESSAGE, strlen (MESSAGE) + 1) < 0) { fprintf (stderr, "[%05d] ", (int) getpid ()); perror ("Erreur ecriture d'un message"); exit (2); } } /******************** Gestionnaire de signal SIGCHLD. ********************/ void Gerant_SIGCHLD (int sig) { /* Quand un enfant est mort, il faut récupérer son état. */ while (waitpid (-1, NULL, WNOHANG) > 0) /* rien */; }