From 3850a32c665a3bdfc9b8e11353c39b2917e02bde Mon Sep 17 00:00:00 2001 From: Flavien Date: Mon, 28 Oct 2019 17:31:10 +0100 Subject: [PATCH] example programs from man getaddrinfo --- client_echo.c | 178 +++++++++++++++++------------------ client_echo.o | Bin 13512 -> 13488 bytes serveur_echo.c | 247 +++++++++++++++++-------------------------------- serveur_echo.o | Bin 13856 -> 13464 bytes 4 files changed, 172 insertions(+), 253 deletions(-) diff --git a/client_echo.c b/client_echo.c index 01df744..92faf73 100755 --- a/client_echo.c +++ b/client_echo.c @@ -1,96 +1,92 @@ +#include +#include +#include #include #include -#include #include -#include -#include -#include -#include -#include - -#define LG_BUFFER 1024 - -int main (int argc, char * argv[]) { - struct sockaddr_in adresse; - int sock; - - char buffer [LG_BUFFER]; - int nb_lus; - - if (argc != 3){ - perror("Nombre d'arguments invalides, vous devez entrer deux arguments"); - exit(-1); - } - - - // Serveur auquel on se connecte - //char * hote = "127.0.0.1"; - char * hote = argv[1]; - - // Port du serveur sur lequel on se connecte0 - //int port = 1234; - int port = atoi(argv[2]); - - struct hostent * hostent; - struct servent * servent; - - // Vider la structure adresse - memset(&adresse, 0, sizeof(struct sockaddr_in)); - - // Donner l'adresse du serveur à la structure adresse - if (inet_aton(hote, & (adresse.sin_addr)) == 0) { - if ((hostent = gethostbyname(hote)) == NULL) { - printf("Erreur : hote %s inconnu \n", hote); - return -1; - } - adresse.sin_addr.s_addr = ((struct in_addr *) (hostent->h_addr))->s_addr; - } - - // Donner un numero de port à la structure adresse - adresse.sin_port = htons(port); - - // Donner la famille de socket à la structure adresse - adresse.sin_family = AF_INET; - - // Créer la socket nommée sock - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { - printf("Erreur : socket\n"); - exit(EXIT_FAILURE); - } - - // Etablir la connexion avec le serveur - if(connect(sock, (struct sockaddr *) & adresse, sizeof (struct sockaddr_in)) < 0 ) { - printf("Erreur : socket"); - return -1; - } - - while (1) { - // Lecture du clavier - if (fgets(buffer, 256, stdin) == NULL) - break; - - if (buffer[strlen(buffer) - 1] == '\n') - buffer[strlen(buffer) - 1] = '\0'; - - // Ecriture des données sur la socket - if (write(sock, buffer, strlen(buffer)) < 0 ) { - printf("Erreur : write\n"); - break; - } - - // Lecture de la réponse du serveur - if ((nb_lus = read(sock, buffer, LG_BUFFER)) == 0 ) { - break; - } - - if (nb_lus < 0) { - printf("Erreur : read\n"); - break; - } - - // Affichage de données recues, variable buffer - printf("%s\n", buffer); - } +#include - return EXIT_SUCCESS; +#define BUF_SIZE 500 + +int +main(int argc, char *argv[]) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int sfd, s, j; + size_t len; + ssize_t nread; + char buf[BUF_SIZE]; + + if (argc < 3) { + fprintf(stderr, "Usage: %s host port msg...\n", argv[0]); + exit(EXIT_FAILURE); + } + + /* Obtain address(es) matching host/port */ + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = 0; + hints.ai_protocol = 0; /* Any protocol */ + + s = getaddrinfo(argv[1], argv[2], &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + exit(EXIT_FAILURE); + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully connect(2). + If socket(2) (or connect(2)) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) + break; /* Success */ + + close(sfd); + } + + if (rp == NULL) { /* No address succeeded */ + fprintf(stderr, "Could not connect\n"); + exit(EXIT_FAILURE); + } + + freeaddrinfo(result); /* No longer needed */ + + /* Send remaining command-line arguments as separate + datagrams, and read responses from server */ + + for (j = 3; j < argc; j++) { + len = strlen(argv[j]) + 1; + /* +1 for terminating null byte */ + + if (len + 1 > BUF_SIZE) { + fprintf(stderr, + "Ignoring long message in argument %d\n", j); + continue; + } + + if (write(sfd, argv[j], len) != len) { + fprintf(stderr, "partial/failed write\n"); + exit(EXIT_FAILURE); + } + + nread = read(sfd, buf, BUF_SIZE); + if (nread == -1) { + perror("read"); + exit(EXIT_FAILURE); + } + + printf("Received %ld bytes: %s\n", (long) nread, buf); + } + + exit(EXIT_SUCCESS); } diff --git a/client_echo.o b/client_echo.o index 1f54f4b4788174082ba55b7125f6586e0fff7b13..36d1a3d54ec82b3eb6341e8bc470683deec3f9d3 100755 GIT binary patch delta 2361 zcmZ`*3rtg27(S;IER~j`VkwGTtCg3u#U~HVcwN01oKD48mSKh4uBNoCExH$UT3u4R zI?Rb1E+)dVEYoetVz&j24>a4VZrLQpjHy|WXi^cAx-rA>(f#MNAT!$~_kVu>d zqx%^(Guq9f<}x`%WwKeCfeV5{5(E0sw%;MS2|sorBTS?gVHr|5J# zoTxd*8XR`J*x*KBw~2OS5#6T7MyJ(ocAzG)$tAjxQ#3V#yAklnyvu2Ii>SfoaEZv= z3^=zL)z>$?ZmKt1?IxS`O)xt}h=}K?ueVvZH$YXB)16q~WU|`H<-9C%G;uY#pQtXR z^PzuZoXVK}Ar$`(s3p^yO#Oe6q9i|_OwJ^!H3~Y__!G(Im_&!3M(!u6$xu=XQBAt7 zNr@vU+s1KBn*>xz6f!kVB|4db*kmb+cP99z1)F3dmhF%tBm@+H2CpY)VNWx3=sR=d zNi-_>zG(;MWs1aO5d8b7F8Eb~Kd~*HgP_HR1c>#8x@o=eD0t7&tq@i{1zdpdJY@v! zEOi1Xd>s5C{u8Q(_|NDhLVPDsU| wUS+Zx56(j@9$_$OJzWTiqc9>N;tn0RZ{< zA#dvtaxd`nLtuJ=#`!KlXLqKt&Q3u7@y<-(jdiw*;{1Gv;NwT`nLrxxuT5c0fGYfm z$6qe>{R|0@vKqtQ*5RnTFouJs_z}S`Wcc}Efq_Z^Cn*FirOH3xB$||29If5fj}qp z3OP>EequB1ripxfAIzsO+TxiG!`Mng&x1V{8ls56AsPw`>JxlF0HzEuv29ljZZ99f zFqX1?bmOMJcN6yCIXa!NADm`=YW7~Lq4tVR6&ovj(Tci?4YdK?!&DB{34ub&*Vp(S z*7&X|YxC|1-XWQA{z*dk{ZZmjZ1L2&Oct?})48};9WFQ5>~OldCYMF8*UKj!A`~G< zRgM;0BWHKGx%hD-M>Q6^1C9?1XLA5)5?wSOXSH)Cr=_Jyw7WT7qZ~EEv0*jY3}%zn zCN^^H^pVpOX;ULwCpL)IonX~L?(J{5MOUmCED6s@C@Tg|kA%~IN27G1r$?hv`iuGr z_y*vQVF=#=r(?Mdyfzw*&d20{QY&d5B`1`6Y$UgoIi)hd%fLVO%mm?Oc#RN$js9LM zl&W_nRSI_IgIW#m+wex7kjm5*(hNvX9&l5GovDWvq%W&nQmrJJv)V8whiCnQ2ZPpZ zwFD26-Luc(YVw*k9jk~#t4>Hm!=R}p#?;_`?L#anR*^k(58z>vrZY&&m84QPPxCu` zZVqWsJI6u6XU|9EL5>=)A(wR7Y1Q!yY|Oin?AEDiJ)k=n-OFePqn|T+hEmN<$gcX2 z>~|UFDS1h!E>XY$(j*$x@mvR))DF>Ww)u~J_Rv` zN&uxonW*!*tb9B=B98&t_(5F7*82+Sou|f5ChukRFr}I=X)n;@^Vv=^{8frcq_?*g zZs)0*g{;P8)IRZ>Lk$_(ovYSp;k-$k(AgMhNpN?r8I$b%87UJlS+YJ~o5(IpV#$Aj zoXl5DieH-KYJLfsQ&2=Zq&=iwgha%0pk*~xk!b(NM4a4 p`Pn}?rlO^CV`?lIcHqZF(!PK2fOIX&`3I>E2jc($ delta 2349 zcmZuze{54l9KU;AM>p1A3|2bW_Lv(R8!Ia)Dqw6Gg*P)`s6#X)rEIUGfwj=SA|v9M zWyrHB7A_q?zMvwZh7DD-RJZD z-hJ>l2&*6Jsl!~$$ZG|Zr$W@dwqV-I^SlIY|s{J-wygDkzAZsN)BtAFh_1{ zEriP*H;JZ>{vl+7kG62JFApIO-6QtgC@vtUb1l~N=`j9o8P7CLcOki*Yr*4*cFY~? zSca-%70P!ln@+S0zXb-g#q7I!PyY6R(k)%n8B0(Nd zD!@o~-4kN2!Bcd<{WK0reEtyJ02N}*IYJa%K6d|%j zLE&;0J_pgPhG_ceY|1h)>7yat?1Z#}g#z(RgaD#Qc3qCT?io)eVZ~xF^UAItyaTR5 z4xOT|{qz{l&?~JR1y=5IU5{+JjymaXOX+S;{s+6IMoI^bBer-j>blN0BFNvtob7=2 zBs(X8{a;|F#&Z^&)Oh{?Pa!&C*?1mu+%pK7>Zd19_x~*z2|Y>Uw$s!`C50{^L`p;y zZ2WSYmU_&~55x4#nffhE)8|xn)D@^&O37!1Sd98XplXac>Pnpk2=XmhUHJ{zTT339 zokDQx%(hFZ24mTEHL~R@l4_}BZnLP{G3qw)u}}^GaI*~Z9>0a-Z0i@k_S%eP+h9is zdE?GEoXeeZ%Gu(4y(w0?-Nd67Ay!BAYmM?hjq;VIX}=4RKXt-a4>d{|OePS{u)J$Y zpksAVOo2yfy?ZILS&6vIJ& z4!rf)pV=RcxCf!4L~nnz99TTKrafh&9F2v5??od-Li?{3wp`yoeF*Y(9`s$f=L+Q^9rchcgow>p&Y2#NSB*A2NV<(xb3TJPbd*ZB$)H!lM^9@3 zy@XDKX*<`T&(*xl6^zlL1pvJR9~vRoj09VS1OIJo0_Qe65j zMr2><_gG2z$}AjKNcWU8_Tzf$o82_yL%9XViL-n{;$ZnT%{DQE(^J;AQ5H9n;VO%L1=yH5E86=+d?Ljk+dSNO)+Fki z7X@}4G9U*To?2zCN{^E8t4v$1s?dI7ud-M_O|y6NRhXR|bdRzqk~9i@ne}fld7sJ> zJ^aklxH6eZPl>F6vnr{b1wB@?tb5oBV^KVlzO?buM0d3pucMX9;aJqvIKRO?(>Bxg zoLaWBA$Fs)A-CA(kvw2b3tBeCYGXE}7C~aDDJKmz_BvJ!vn||iI-ffvd4f`QO(Z*N zUMw1|v{_yxS@VjSmdtE4ueO@FYNr~q>u4fb8^DSBx>XqN_b%IvJVmRfLP=b(4PfqX z4cT39%g@{>cnTNmXPYzkJEK1&X8VlYb`xo~*XPI6|LDXGi4W{W95#`|v%bKsWZARN N=RHUtbOEeY_CK61`-lJl diff --git a/serveur_echo.c b/serveur_echo.c index fe9ea6e..2781ce3 100755 --- a/serveur_echo.c +++ b/serveur_echo.c @@ -1,168 +1,91 @@ -#define _GNU_SOURCE +#include #include #include -#include #include -#include -#include -#include -#include +#include #include +#include -int cree_socket_stream (const char * nom_hote, const int num_port, const char * nom_proto); -int affiche_adresse_socket (int sock); -int serveur_tcp (void); -void traite_connexion (int sock); - -int cree_socket_stream (const char * nom_hote, const int num_port, const char * nom_proto){ - int sock; - struct sockaddr_in adresse; - struct hostent * hostent = NULL; - struct protoent * protoent = NULL; - - if (nom_hote != NULL) { - if ((hostent = gethostbyname(nom_hote)) == NULL) { - printf("Erreur : gethostbyname\n"); - return -1; - } - } - - if ((protoent = getprotobyname(nom_proto)) == NULL) { - printf("Erreur : getprotobyname\n"); - return -1; - } - - // Créer la socket nommée sock - if((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { - printf("Erreur : socket"); - return -1; - } - - // Mise à 0 de la structure adresse - memset(& adresse, 0, sizeof(struct sockaddr_in)); - - // Donner la famille de socket dans la structure adresse - adresse.sin_family = AF_INET; - - adresse.sin_port = num_port; - - // Donner un numero de port à la structure adresse - if (num_port > 1024) { - adresse.sin_port = htons(num_port); - } - else { - adresse.sin_port = htons(0); - } - - // Donner l'adresse du serveur à la structure adresse - if (hostent != NULL) { - adresse.sin_addr.s_addr = ((struct in_addr *) (hostent->h_addr))->s_addr; - } - else { - adresse.sin_addr.s_addr = htonl(INADDR_ANY); - } - // Pattacher un port a la socket sock - if (bind(sock, (struct sockaddr *) & adresse, sizeof(struct sockaddr_in)) < 0) { - close(sock); - printf("Erreur : bind\n"); - return -1; - } - return sock; -} - -int affiche_adresse_socket (int sock) { - struct sockaddr_in adresse; - socklen_t longueur; - - longueur = sizeof(struct sockaddr_in); - - if (getsockname(sock, & adresse, & longueur) < 0) { - printf("Erreur : getsockname\n"); - return -1; - } - printf ("IP = %s, Port = %u \n", inet_ntoa(adresse.sin_addr), ntohs(adresse.sin_port)); - return 0; -} - -int serveur_tcp (void) { - int sock_contact; // Socket créée du côté du serveur - int sock_connectee; // Socket du côté du client qui se connecte - struct sockaddr_in adresse; - socklen_t longueur; - - longueur = sizeof(struct sockaddr_in); - - // Appeler la fonction cree_socket_stream() pour créer la socket nommée socket_contact - // Choisir : nom de l'hote, le num du port, le protocole - - sock_contact = cree_socket_stream("0.0.0.0", 1234, "tcp"); - - if (sock_contact < 0) { - return -1; - } - - // Placer le serveur en écoute sur la socket nommée sock_contact - listen(sock_contact, 5); - - printf("Mon adresse >> "); - affiche_adresse_socket(sock_contact); - - while (1) { - // tester si un client se connecte : appel accept() bloquant - // Le retour de accept() est une nouvelle socket nommé sock_connectee - // avec laquelle l'échange avec le client aura lieu - - sock_connectee = accept(sock_contact, & adresse, & longueur); - - if (sock_connectee < 0) { - printf("Erreur : accept\n"); - return -1; - } - - printf("Nouveau client\n"); - - switch (fork()) { - case 0 : // Code du fils - close(sock_contact); - traite_connexion(sock_connectee); - exit(EXIT_SUCCESS); - case -1 : - printf("Erreur : fork\n"); - return -1; - default : // Code du pere - close(sock_connectee); - } - } - return 0; -} - -void traite_connexion (int sock){ - char buffer[256]; - int longueur; - - while (1) { - // Lire la socket et récupérer le nombre d'octets lus dans la variable longueur - longueur = read(sock, buffer, 256); - - if (longueur < 0) { - printf("Erreur : read\n"); - exit(EXIT_SUCCESS); - } - - if (longueur == 0) { - break; - } - - printf("J'ai lu %d bytes\n",longueur); - // Pour le client telnet : - //buffer[longueur-2] = '\0'; - - // Ecrire la variable buffer sur la socket - write(sock, buffer, longueur); - } - close(sock); -} - -int main (int argc, char * argv[]) { - return serveur_tcp(); +#define BUF_SIZE 500 + +int +main(int argc, char *argv[]) +{ + struct addrinfo hints; + struct addrinfo *result, *rp; + int sfd, s; + struct sockaddr_storage peer_addr; + socklen_t peer_addr_len; + ssize_t nread; + char buf[BUF_SIZE]; + + if (argc != 2) { + fprintf(stderr, "Usage: %s port\n", argv[0]); + exit(EXIT_FAILURE); + } + + memset(&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + hints.ai_protocol = 0; /* Any protocol */ + hints.ai_canonname = NULL; + hints.ai_addr = NULL; + hints.ai_next = NULL; + + s = getaddrinfo(NULL, argv[1], &hints, &result); + if (s != 0) { + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); + exit(EXIT_FAILURE); + } + + /* getaddrinfo() returns a list of address structures. + Try each address until we successfully bind(2). + If socket() (or bind()) fails, we (close the socket + and) try the next address. */ + + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; /* Success */ + + close(sfd); + } + + if (rp == NULL) { /* No address succeeded */ + fprintf(stderr, "Could not bind\n"); + exit(EXIT_FAILURE); + } + + freeaddrinfo(result); /* No longer needed */ + + /* Read datagrams and echo them back to sender */ + + for (;;) { + peer_addr_len = sizeof(struct sockaddr_storage); + nread = recvfrom(sfd, buf, BUF_SIZE, 0, + (struct sockaddr *) &peer_addr, &peer_addr_len); + if (nread == -1) + continue; /* Ignore failed request */ + + char host[NI_MAXHOST], service[NI_MAXSERV]; + + s = getnameinfo((struct sockaddr *) &peer_addr, + peer_addr_len, host, NI_MAXHOST, + service, NI_MAXSERV, NI_NUMERICSERV); + if (s == 0) + printf("Received %ld bytes from %s:%s\n", + (long) nread, host, service); + else + fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); + + if (sendto(sfd, buf, nread, 0, + (struct sockaddr *) &peer_addr, + peer_addr_len) != nread) + fprintf(stderr, "Error sending response\n"); + } } diff --git a/serveur_echo.o b/serveur_echo.o index a7a9192ae234a68837151d0073ee0ac741d8911a..c7043832c5a6a5caff8b5d2ede1527731634d2d0 100755 GIT binary patch literal 13464 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 QiO8at^n%Ji{{8y@1PGqj+W-In literal 13856 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 F{{tGo7-j$f