Synthèse Socket en C
Mode UDP (non-connecté)
Client UDP #include <errno.h> #include <string.h> int socketUdp ; socketUdp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (socketUdp == -1) { printf("pb socket : %s\n", strerror(errno)); exit(errno); } #include <sys/types.h> #include <sys/socket.h>
Client UDP Taille de la Adresse mémoire donnée à envoyer de la donnée La socket ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); Adresse mémoire d'une variable de type struct sockaddr_in contenant les données correspondant au destinataire : IP, numéro de port, etc Taille de la structure struct sockaddr_in Si le type attendu dans le prototype est un pointeur, il ne faut pas pour autant en déclarer un. Donner l'adresse d'une variable statique est bien plus judicieux !
Client UDP #include <netinet/in.h> #include <arpa/inet.h> struct sockaddr_in { sa_family_t sin_family; // famille d'adresses : AF_INET uint16_t sin_port; // port dans l'ordre des octets réseau struct in_addr sin_addr; // adresse Internet }; struct in_addr { uint32_t s_addr; // adresse dans l'ordre des octets réseau Client UDP int maDonnee ; struct sockaddr_in informationsDestinataire ; int tailleStructure ; int retourSend ; int socketUdp ; socketUdp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); ... informationsDestinataire.sin_family = AF_INET ; informationsDestinataire.sin_port = htons(2222) ; informationsDestinataire.sin_addr.s_addr = inet_addr("172.17.83.110") ; #include <arpa/inet.h> #include <netinet/in.h>
Client UDP int maDonnee ; struct sockaddr_in { sa_family_t sin_family; // famille d'adresses : AF_INET uint16_t sin_port; // port dans l'ordre des octets réseau struct in_addr sin_addr; // adresse Internet }; struct in_addr { uint32_t s_addr; // adresse dans l'ordre des octets réseau Client UDP int maDonnee ; struct sockaddr_in informationsDestinataire ; int tailleStructure ; int retourSend ; int socketUdp ; socketUdp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); ... informationsDestinataire.sin_family = AF_INET ; informationsDestinataire.sin_port = htons(2222) ; informationsDestinataire.sin_addr.s_addr = inet_addr("172.17.83.110") ; maDonnee = 32 ; tailleStructure = sizeof(informationsDestinataire) ;
Client UDP int maDonnee ; struct sockaddr_in { sa_family_t sin_family; // famille d'adresses : AF_INET uint16_t sin_port; // port dans l'ordre des octets réseau struct in_addr sin_addr; // adresse Internet }; struct in_addr { uint32_t s_addr; // adresse dans l'ordre des octets réseau Client UDP int maDonnee ; struct sockaddr_in informationsDestinataire ; int tailleStructure ; int retourSend ; int socketUdp ; socketUdp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); ... informationsDestinataire.sin_family = AF_INET ; informationsDestinataire.sin_port = htons(2222) ; informationsDestinataire.sin_addr.s_addr = inet_addr("172.17.83.110") ; maDonnee = 32 ; tailleStructure = sizeof(informationsDestinataire) ; retourSend = sendto(socketUdp, &maDonnee, sizeof(maDonnee), 0, (struct sockaddr *)&informationsDestinataire, tailleStructure ); if (retourSend == -1) { printf("pb sendto : %s\n", strerror(errno)); exit(errno); }
Client UDP Adresse mémoire de la variable qui prendra la valeur de la donnée reçu Client UDP Taille du type de la donnée à recevoir La socket ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen); Adresse mémoire d'une variable de type struct sockaddr_in qui sera mise à jour avec les données de celui qui a envoyé les données, par la fonction recvfrom Adresse mémoire d'une variable ayant été initialisée avec la taille de la structure struct sockaddr_in
Client UDP variables qui seront mises à jour par la fonction recvfrom int maDonnee, donneeRecu ; struct sockaddr_in informationsDestinataire ; struct sockaddr_in informationsEnvoyeur ; int tailleStructure ; int retourSend, retourRecv ; int socketUdp ; socketUdp = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); ... tailleStructure = sizeof(informationsDestinataire) ; retourSend = sendto(socketUdp, &maDonnee, sizeof(maDonnee), 0, (struct sockaddr *)&informationsDestinataire, tailleStructure ); retourRecv = recvfrom(socketUdp, &donneeRecu, sizeof(donneeRecu), 0, (struct sockaddr *)&informationsEnvoyeur, &tailleStructure ) if (retourRecv == -1) { printf("pb recvfrom : %s\n", strerror(errno)); exit(errno); } printf("donnee recu :%d \n",donneeRecu) ; close(socketUdp) ;
Serveur UDP int fdSocket; struct sockaddr_in infoServeur; struct sockaddr_in infoClient; int retour; int tailleClient; int valRec; fdSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (fdSocket == -1) { printf("pb socket : %s\n", strerror(errno)); exit(errno); } infoServeur.sin_family = AF_INET; infoServeur.sin_port = htons(2222); infoServeur.sin_addr.s_addr = htonl(INADDR_ANY); //IP du serveur dans l'ordre des octets du reseau //attachement ip-port retour = bind(fdSocket, (struct sockaddr*) &infoServeur, sizeof(infoServeur)); if (retour == -1) printf("pb sendto : %s\n", strerror(errno)); tailleClient = sizeof(infoClient);
Serveur UDP int fdSocket; struct sockaddr_in infoServeur; struct sockaddr_in infoClient; int retour; int tailleClient; int valRec; fdSocket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); ... tailleClient = sizeof(infoClient); while (1==1){ retour = recvfrom(fdSocket, &valRec, sizeof(valRec), 0, (struct sockaddr *) &infoClient, &tailleClient); if (retour == -1) { printf("pb recvfrom : %s\n", strerror(errno)); exit(errno); } printf("message du client %s/%d: %d\n", inet_ntoa(infoClient.sin_addr), infoClient.sin_port, valRec); valRec=-valRec; retour = sendto(fdSocket, &valRec, sizeof(valRec), 0, (struct sockaddr *)&infoClient, sizeof(infoClient)); printf("pb sendto : %s\n", strerror(errno)); exit(0);
Mode UDP A retenir : Les informations concernant celui à qui l'on envois doivent être passées en paramètre de la fonction sendto. Les informations concernant celui qui a envoyé sont mises à jour via la fonction revcfrom. Dans les deux cas, il s'agit d'une variable de type : struct sockaddr_in Attention à la fonction recvfrom qui à des passages de paramètres par adresse.
Mode TCP (connecté)
Client TCP int socketTcp ; socketTcp = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (socketTcp == -1) { printf("pb socket : %s\n", strerror(errno)); exit(errno); }
Client TCP La socket int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); Adresse mémoire d'une variable de type struct sockaddr_in contenant les données correspondant au destinataire : IP, numéro de port, etc Taille de la structure struct sockaddr_in
Client TCP int fdSocket; struct sockaddr_in informationServeur; int retour; int tailleClient; informationServeur.sin_family = AF_INET; informationServeur.sin_port = htons(5555); informationServeur.sin_addr.s_addr = inet_addr("172.17.83.110"); fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fdSocket == -1) { printf("pb socket : %s\n", strerror(errno)); exit(errno); } //demande de connection au serveur retour = connect(fdSocket, (struct sockaddr *) &informationServeur, sizeof(informationServeur)); if (retour == -1) printf("pb connect : %s\n", strerror(errno));
Client TCP adresse en mémoire de la donnée à envoyer La socket ssize_t write(int fildes, const void *buf, size_t nbyte); #include <unistd.h> taille, en octets, de la donnée à envoyer
Client TCP int fdSocket; struct sockaddr_in informationServeur; int retour; int tailleClient; int valeurEnv, valRetour ; fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ... retour = connect(fdSocket, (struct sockaddr *) &informationServeur, sizeof(informationServeur)); // envoyer donnees au serveur valeurEnv = 32 ; retour = write(fdSocket, &valeurEnv, sizeof(valeurEnv)); if (retour == -1) { printf("pb write : %s\n", strerror(errno)); exit(errno); }
Client TCP adresse de la variable recevant la valeur envoyée La socket ssize_t read(int fildes, void *buf, size_t nbyte); nombre d'octets, au maximum , réceptionnables
Client TCP int fdSocket; struct sockaddr_in informationServeur; int retour; int tailleClient; int valeurEnv, valRetour ; fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ... retour = connect(fdSocket, (struct sockaddr *) &informationServeur, sizeof(informationServeur)); // envoyer donnees au serveur valeurEnv = 32 ; retour = write(fdSocket, &valeurEnv, sizeof(valeurEnv)); // reception en provenance du serveur retour = read(fdSocket, &valRetour, sizeof(valRetour)); if (retour == -1) { printf("pb read : %s\n", strerror(errno)); exit(errno); } printf("valeur provenant du serveur :%d\n",valRetour) ; close(fdSocket) ;
Client TCP A retenir Une seule structure sockaddr_in C'est la fonction connect qui va permettre la liaison au serveur (c'est elle qui effectue le handshake). read et write, fonctionnent comme des fonctions de lecture et d'écriture dans un fichier.
Serveur TCP int fdSocket; int socketClient struct sockaddr_in infoServeur; struct sockaddr_in infoClient; int retour; int tailleClient; int valRec; fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (fdSocket == -1) { printf("pb socket : %s\n", strerror(errno)); exit(errno); } infoServeur.sin_family = AF_INET; infoServeur.sin_port = htons(2222); infoServeur.sin_addr.s_addr = htonl(INADDR_ANY); //IP du serveur dans l'ordre des octets du reseau //attachement ip-port retour = bind(fdSocket, (struct sockaddr*) &infoServeur, sizeof(infoServeur)); if (retour == -1) printf("pb bind : %s\n", strerror(errno)); tailleClient = sizeof(infoClient);
Serveur TCP int fdSocket; int socketClient struct sockaddr_in infoServeur; struct sockaddr_in infoClient; int retour; int tailleClient; int valRec; fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ... // mise en place d'une file d'attente de 10 retour = listen (fdSocket,10) ; if (retour == -1) { printf("pb listen : %s\n", strerror(errno)); exit(errno); }
Client TCP Adresse mémoire d'une variable ayant été initialisée avec la taille de la structure struct sockaddr_in Client TCP La socket du serveur int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); Le descripteur de socket permettant la communication avec le client Adresse mémoire d'une variable de type struct sockaddr_in qui sera mise à jour avec les données de celui qui se connecte par la fonction connect
Serveur TCP int fdSocket; int socketClient struct sockaddr_in infoServeur; struct sockaddr_in infoClient; int retour; int tailleClient; int valRec; fdSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); ... tailleClient = sizeof(infoClient); while (1==1){ // attente de connexion socketClient=accept(fdSocket, (struct sockaddr *)&infoClient,&tailleClient) ; if (socketClient== -1) { printf("pb accept : %s\n", strerror(errno)); exit(errno); } retour = read(socketClient, &valRec, sizeof(valRec)); if (retour == -1) printf("pb read : %s\n", strerror(errno)); valRec=-valRec ; retour = write(socketClient, &valRec, sizeof(valRec));
Serveur TCP A retenir La fonction listen permet de fixer la longueur de la file d'attente La fonction accept retourne le descripteur de socket qui doit être utilisé pour communiquer avec le client