Créer un serveur UDP
Notre objectif est de créer un serveur UDP minimal : le serveur envoie la lettre suivante dans l'alphabet lorsque'il recoit une lettre. Il renvoie le caractère '!' s'il reçoit un caractère qui n'est pas une lettre ou s'il reçoit la lettre 'z' ou la lettre 'Z'.
Se documenter
Code du serveur
/** * @brief Reçoit une lettre du client. Il envoie au client la lettre suivante dans l'alphabet. * Il envoie le caractère '!' s'il reçoit un caractère qui n'est pas une lettre ou s'il reçoit la lettre 'z' ou la lettre 'Z'. */ #include <string.h> // pour memset() #include <sys/types.h> // pour socket(), setsockopt(), bind(), recvfrom(), sendto() #include <sys/socket.h> // pour socket(), setsockopt(), bind(), recvfrom(), sendto() #include <stdio.h> // pour fprintf(), perror() #include <arpa/inet.h> // pour htonl(), htons() // Numéro de port du serveur #define NUMERO_PORT_SERVEUR 40000 int main() { struct sockaddr_in coupleIPPortServeur; struct sockaddr_in coupleIPPortClient; socklen_t longueurClient; int maSocket; int optval; char lettre; char lettreReponse; // Initialiser les structures a des octets de valeurs 0 memset(&coupleIPPortServeur, 0, sizeof(struct sockaddr_in)); // Creer la socket serveur en mode UDP if ((maSocket = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {perror("socket"); return -1;} // Reutiliser le meme port en cas d'interruption brutal du serveur optval = 1; setsockopt(maSocket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); // Ouvrir un port coupleIPPortServeur.sin_family = AF_INET; coupleIPPortServeur.sin_addr.s_addr = htonl(INADDR_ANY); coupleIPPortServeur.sin_port = htons(NUMERO_PORT_SERVEUR); if (bind(maSocket, (struct sockaddr *)(&coupleIPPortServeur), sizeof(struct sockaddr_in)) == -1) {perror("bind"); return -1;} while (1) { lettreReponse = '!'; longueurClient = sizeof(coupleIPPortClient); // Recevoir la requête if (recvfrom(maSocket, &lettre, sizeof(lettre), 0, (struct sockaddr *)(&coupleIPPortClient), &longueurClient) == -1) {perror("recvfrom"); return -1; } // Traiter la requete if ((lettre >= 'a' && lettre < 'z') || (lettre >= 'A' && lettre < 'Z')) lettreReponse = lettre + 1; // Envoyer la réponse if (sendto(maSocket, &lettreReponse, sizeof(lettreReponse), 0, (struct sockaddr *)(&coupleIPPortClient), longueurClient) == -1) {perror("sendto"); return -1;} } return 0; }
Tester
Vérifier que le port 40000
de notre serveur UDP
est ouvert
Commande ss
: another utility to investigate sockets
Options :
-l : Display only listening sockets.
-n : Do not try to resolve service names.
-u : Display UDP sockets.
-p : Show process using socket.
doe@debian:~$ ss -lnup | grep serveur UNCONN 0 0 0.0.0.0:40000 0.0.0.0:* users:(("serveurUdp",pid=1222,fd=3))
Valider le protocole applicatif
J'utilise, pour valider le serveur, le client UDP correspondant.
doe@debian:~$ ./clientUdp usage : clientUdp <adresse_IP_serveur> <numero_de_port_serveur> <lettre> exemple : clientUdp 192.168.1.11 40000 a doe@debian:~$ ./clientUdp 192.168.1.101 30000 d recvfrom: Resource temporarily unavailable communiquerAvecLeServeur : echec doe@debian:~$ ./clientUdp 192.168.1.101 40000 d J'ai émis : d, j'ai reçu : e doe@debian:~$ ./clientUdp 192.168.1.101 40000 D J'ai émis : D, j'ai reçu : E doe@debian:~$ ./clientUdp 192.168.1.101 40000 z J'ai émis : z, j'ai reçu : ! doe@debian:~$ ./clientUdp 192.168.1.101 40000 Z J'ai émis : Z, j'ai reçu : ! doe@debian:~$ ./clientUdp 192.168.1.101 40000 ? J'ai émis : ?, j'ai reçu : !