Programmation Avancée en C


socket_TCP_client_ipv6.c

00001 #include <stdio.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004 #include <unistd.h>
00005 #include <sys/socket.h>
00006 #include <netinet/in.h>
00007 #include <arpa/inet.h>
00008 #define _POSIX_C_SOURCE 2 /* Nécessaire sur certains Linux. */
00009 #include <netdb.h> 
00010 
00011 #define MAX_SIZE 256
00012 
00013 void error(char * msg) { // cf. ligne /*@\ref{network::socket_TCP_client::error} du listing~\ref{network::socket_TCP_client}@*/
00014     perror(msg);
00015     exit(EXIT_FAILURE);
00016 }
00017     /*** Gestion des interactions avec le serveur. ***/
00018 void doit(int sockfd, struct addrinfo * serv) { 
00019     char      requete[MAX_SIZE] = "Luc, je suis ton père!", reponse[MAX_SIZE];
00020     char      addr[INET6_ADDRSTRLEN], *ptr = "";  // Pour l'affichage de l'adresse.
00021     size_t    request_size = strlen(requete) + 1;
00022     in_port_t port; 
00023 
00024     ssize_t n = send(sockfd, requete, request_size, 0); // Envoi de la requête.
00025     if (n != request_size) error("[send]");
00026     switch (serv->ai_family) {
00027     case AF_INET:  {
00028         struct sockaddr_in  *sin  = (struct sockaddr_in *)  serv->ai_addr;
00029         ptr = (char *) inet_ntop(AF_INET, &sin->sin_addr, addr, sizeof(addr));
00030         port = sin->sin_port;
00031         break;     }
00032     case AF_INET6: {
00033         struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) serv->ai_addr;
00034         ptr = (char *) inet_ntop(AF_INET6, &sin6->sin6_addr, addr, sizeof(addr));
00035         port = sin6->sin6_port;
00036         break;     }
00037     }
00038     if (!ptr) printf("Requête envoyée à %s port %d : <%s> (%ld octets envoyés)\n",
00039                      ptr, port, requete, (long) n);
00040 
00041     n = recv(sockfd, reponse, MAX_SIZE-1, 0); // La réponse du serveur.
00042     if (n < 0) error("[recv]");
00043     reponse[n] = '\0'; // Précaution pour l'affichage.
00044     printf("Réponse obtenue: <%s> (%lu octets)\n", reponse, (long) n);  
00045 }
00046 
00047 int main(int argc, char* argv[]) 
00048 {
00049     char * servname = "localhost";    // Serveur par défaut.
00050     char * port     = "6666";         // Port du service par défaut.
00051     struct addrinfo hints, *res;
00052     int err, sockfd = -1;
00053 
00054     switch (argc) { // Traitement des arguments de la ligne de commande.
00055     case 3:  port     = argv[2];
00056     case 2:  servname = argv[1]; break;
00057     case 1:  break;
00058     default: fprintf(stderr, "Usage: %s [servname [port]]\n",argv[0]);
00059              return EXIT_FAILURE;
00060     }
00061     /*** Construction de l'adresse de socket du serveur ***/
00062     memset(&hints, 0, sizeof(hints));
00063     hints.ai_flags = AI_CANONNAME;  
00064     hints.ai_family = AF_UNSPEC;      
00065     hints.ai_socktype = SOCK_STREAM;  // Sockets connectée.
00066     if ((err = getaddrinfo(servname, port, &hints, &res)) < 0)  {
00067         if (err == EAI_SYSTEM) error("[getaddrinfo]");
00068         fprintf(stderr, "[getaddrinfo] on %s : %s\n", servname, gai_strerror(err));
00069         return EXIT_FAILURE;
00070     }
00071     for(; res != NULL; res = res->ai_next) {
00072         sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00073         if (sockfd < 0) continue;
00074         if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0) {
00075             close(sockfd);
00076             sockfd = -1;
00077             continue;
00078         }
00079         break; // Si on arrive ici, on a réussi à se connecter au serveur.
00080     }
00081     if (sockfd  < 0)   error("[socket ou connect]"); 
00082     doit(sockfd, res); // Gestion des requêtes.
00083 
00084     close(sockfd);     // Fermeture de la socket.
00085     freeaddrinfo(res); // Ne pas oublier de libérer l'espace alloué à res!
00086     return EXIT_SUCCESS;
00087 }
00088