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 : !