Programmation Avancée en C


echo_UDP_client.c

00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <unistd.h>
00004 #include <netinet/in.h>
00005 #include <sys/types.h>
00006 #include <sys/socket.h>
00007 #include <arpa/inet.h>
00008 #define _POSIX_C_SOURCE 2 /* Nécessaire sur certains Linux. */
00009 #include <netdb.h>
00010 #include <string.h>
00011 
00012 #define MAX_SIZE 256
00013 
00014 void error(char * msg);      // Cf. ligne /*@\ref{network::socket_TCP_client::error} du listing~\ref{network::socket_TCP_client}@*/.
00015 
00016 void doit(int sockfd, struct sockaddr_in * serv) { // Traitement coté client.
00017     char linetosend[MAX_SIZE+1], reponse[MAX_SIZE];
00018     ssize_t n;
00019     struct sockaddr_in reply_addr;
00020     socklen_t len = sizeof(reply_addr);
00021     memset(&reply_addr, 0, len);
00022 
00023     printf("Entrez une phrase : ");
00024     while ( fgets(linetosend, MAX_SIZE, stdin) != NULL ) {
00025         n = sendto(sockfd, linetosend, strlen(linetosend), 0, 
00026                    (struct sockaddr *) serv, sizeof(*serv));
00027         if (n != strlen(linetosend)) error("[sendto]");
00028 
00029         n = recvfrom(sockfd, reponse, MAX_SIZE-1, 0, 
00030                      (struct sockaddr *)&reply_addr , &len);
00031         if (n < 0) error("[recv]");
00032 
00033         if ((len != sizeof(*serv)) || memcmp(&reply_addr, serv, len)) {
00034             printf("Réponse de %s (ignorée).\n", inet_ntoa(reply_addr.sin_addr));
00035             continue;
00036         }
00037         reponse[MAX_SIZE] = '\0'; // Précaution pour l'affichage.
00038         printf("Message reçu : %s\n---\nEntrez une phrase : ", reponse);
00039     }
00040 }
00041 
00042 int main(int argc, char* argv[]) 
00043 {
00044     char * servname = "localhost";
00045     char * port     = "6666";
00046     struct addrinfo hints, *res;
00047     int err, sockfd = -1;
00048 
00049     /***Traitement des arguments de la ligne de commande. ***/
00050     switch (argc) {
00051     case 3:  port     = argv[2];
00052     case 2:  servname = argv[1]; break;
00053     case 1:  break;
00054     default: fprintf(stderr, "Usage: %s [servname [port]]\n",argv[0]);
00055              return EXIT_FAILURE;
00056     }
00057     /*** Construction de l'adresse de socket du serveur. ***/
00058     memset(&hints, 0, sizeof(hints));
00059     hints.ai_flags    = AI_CANONNAME; // On veut une résolution de nom.
00060     hints.ai_family   = AF_INET;      // Adresse IPv4 uniquement.
00061     hints.ai_socktype = SOCK_DGRAM;   // Sockets non connectée.
00062     if ((err = getaddrinfo(servname, port, &hints, &res)) < 0)  {
00063         if (err == EAI_SYSTEM) error("[getaddrinfo]");
00064         fprintf(stderr, "[getaddrinfo] on %s : %s\n", servname, gai_strerror(err));
00065         return EXIT_FAILURE;
00066     }
00067     for(; res != NULL; res = res->ai_next) {
00068         /*** Création d'une socket. ***/ 
00069         sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00070         if (sockfd < 0) continue;
00071         break; // Si on arrive ici, on a réussi à créer la socket.
00072     }
00073     if (sockfd  < 0)   error("[socket]"); 
00074     doit(sockfd, (struct sockaddr_in *) res->ai_addr); // gestion des requêtes
00075     // ... Le reste est inchangé.
00076     
00077     /*** Fermeture de la socket. ***/
00078     close(sockfd);     
00079     freeaddrinfo(res); // Ne pas oublier de libérer l'espace alloué à res!
00080     return EXIT_SUCCESS;
00081 }
00082 
00083 void error(char * msg) {
00084     perror(msg);
00085     exit(EXIT_FAILURE);
00086 }