Programmation Avancée en C


socket_TCP_server_ipv6.c

00001 #include <stdio.h> 
00002 #include <stdlib.h> 
00003 #include <unistd.h>
00004 #include <netinet/in.h>
00005 #include <sys/socket.h>
00006 #include <sys/types.h>
00007 #include <sys/wait.h>
00008 #include <string.h>    
00009 #include <arpa/inet.h>
00010 
00011 #define MAX_SIZE 256
00012 #define NUMPORT 6666     // Le port où les utilisateurs se connecteront.
00013 #define BACKLOG 14       // Nombre maximal de connections acceptées en attente.
00014 
00015 void error(char * msg);      // Cf. ligne /*@\ref{network::socket_TCP_client::error} du listing~\ref{network::socket_TCP_client}@*/.
00016 void traitement(int sockfd); // Cf. listing /*@\ref{network::socket_TCP_server::doit}@*/.
00017 int main() 
00018 {
00019     int listenfd, connfd;            // connfd: socket de travail.
00020     struct sockaddr_in6 serv_addr;   // Adresse locale du serveur.
00021     struct sockaddr_in6 client_addr; // Adresse du client qui se connecte.
00022     char tmp[INET6_ADDRSTRLEN];      // Pour l'affichage de l'adresse IP du client.
00023     
00024     /* Création de l'adresse de socket locale du serveur. */
00025     memset(&serv_addr, 0, sizeof(serv_addr)); // Remplissage à 0.
00026     serv_addr.sin6_family  = AF_INET6;
00027     serv_addr.sin6_addr    = in6addr_any;
00028     serv_addr.sin6_port    = htons(NUMPORT);    
00029     /* Création d'une socket. */ 
00030     if ( (listenfd = socket(PF_INET6, SOCK_STREAM, 0)) < 0) 
00031         error("[socket]");
00032     int on = 1,
00033         rc = setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, 
00034                         (void *)&on, sizeof(on)); 
00035     if (rc < 0) error("[setsockopt(SO_REUSEADDR)]");
00036     /* Attachement de la socket. */
00037     if ( bind(listenfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) 
00038         error("[bind]");
00039     /* On en fait une socket d'écoute. */ 
00040     if ( listen(listenfd, BACKLOG) < 0) error("[listen]"); 
00041     if (inet_ntop(AF_INET6, &serv_addr, tmp, INET6_ADDRSTRLEN))
00042     printf("Serveur: en écoute à l'adresse %s sur le port %d\n",
00043            tmp, ntohs(serv_addr.sin6_port));
00044     while(1) { // Boucle principale pour accept().
00045         socklen_t addr_len = sizeof(client_addr);
00046         connfd = accept(listenfd, (struct sockaddr *) &client_addr, &addr_len); 
00047         if (connfd < 0) {
00048             perror("[accept]");
00049             continue;
00050         }
00051         if (inet_ntop(AF_INET6, &client_addr, tmp, INET6_ADDRSTRLEN))
00052             printf("Serveur: connexion acceptée avec %s (port %d)\n", 
00053                    tmp, ntohs(client_addr.sin6_port));
00054  // ... Le reste est inchangé.
00055 
00056         /* Gestion concurrente des connexions acceptée */
00057         if (! fork()) { // Creation d'un processus fils /*@\label{network::socket_TCP_server::fork}@*/
00058             close(listenfd);    // fermeture de la socket d'écoute pour le fils
00059             traitement(connfd); // Traitement de la requête
00060             exit(EXIT_SUCCESS); // sortie du processus fils
00061         }
00062         close(connfd); // le père ferme la socket de travail
00063         while( waitpid( -1, NULL, WNOHANG) > 0); // Nettoyage des processus fils /*@\label{network::socket_TCP_server::waitpid}@*/
00064     }
00065     /* Fermeture de la socket */
00066     close(listenfd);     
00067     return EXIT_SUCCESS;
00068 }
00069 
00070 void error(char * msg) {
00071     perror(msg);
00072     exit(EXIT_FAILURE);
00073 }
00074 
00075 /**
00076  * Traite une connexion acceptée par envoi/reception de données
00077  */
00078 void traitement(int sockfd) {
00079     char requete[MAX_SIZE], reponse[MAX_SIZE] = "Nonnnnnnnnn !";
00080     size_t  answer_size = strlen(reponse)+1;
00081 
00082     ssize_t n = recv(sockfd, requete, MAX_SIZE-1, 0); // Reception
00083     if (n < 0) error("[recv]");
00084     requete[n] = '\0'; // Précaution pour l'affichage
00085     printf(" - Requête reçue: <%s> (%ld octets reçus)\n", requete, (long) n);
00086     
00087     n = send(sockfd, reponse, answer_size, 0); // Emission de la réponse
00088     if (n != answer_size ) error("[send]");
00089     printf(" - Réponse émise: <%s> (%ld octets envoyés)\n", reponse, (long) n);
00090 }