Comment un client UDP envoie des datagrammes : flux bind(), sendto(), recvfrom()
Cycle de vie client UDP (Sockets POSIX)
Contrairement à TCP, UDP est sans connexion. Le client doit explicitement lier un port local (optionnel mais recommandé) et spécifier la destination à chaque envoi.
Séquence d'appels système pas à pas
1. Créer le socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0); if (sockfd < 0) perror("socket"); 2. Lier le port local (Optionnel mais recommandé)
struct sockaddr_in local = {0}; local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); local.sin_port = htons(0); // 0 = OS attribue port éphémère bind(sockfd, (struct sockaddr*)&local, sizeof(local)); Le bind permet au serveur de répondre sur un port connu et active les règles pare-feu.
3. Résoudre l'adresse serveur
struct addrinfo hints = {0}, *res; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; getaddrinfo("server.example.com", "5000", &hints, &res); // res->ai_addr contient maintenant sockaddr_in destination 4. Envoyer le datagramme
char *msg = "Hello UDP"; sendto(sockfd, msg, strlen(msg), 0, res->ai_addr, res->ai_addrlen);
sendto arguments : socket, buffer, longueur, flags (0), sockaddr destination, longueur sockaddr.
5. Recevoir la réponse (Optionnel)
char buf[1500]; struct sockaddr_in from; socklen_t fromlen = sizeof(from); ssize_t n = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&from, &fromlen); if (n > 0) process(buf, n, &from);
recvfrom bloque jusqu'à l'arrivée d'un datagramme. from contient IP/port de l'expéditeur.
6. Nettoyage
freeaddrinfo(res); close(sockfd);
Différences clés avec TCP
| Aspect | TCP | UDP |
|---|---|---|
| Connexion | connect() établit | Pas de connexion ; sendto spécifie dest chaque fois |
| Fiabilité | Garantie, ordonnée | Meilleur effort ; peut perdre, réordonner, dupliquer |
| Contrôle flux | Oui (fenêtre) | Non (l'appli doit cadencer) |
| Usage typique | Web, email, SSH | DNS, NTP, VoIP, gaming, streaming, IoT |
Pièges courants
- Oublier
bind()→ serveur répond sur port éphémère ; NAT/pare-feu peut drop. - Ne pas vérifier valeurs retour
sendto/recvfrom. - Supposer frontières datagramme préservées (elles le sont, mais taille limitée ~64 Ko, MTU pratique ~1500).
recvfrombloquant pour toujours — utilisezselect()/poll()ousetsockopt(SO_RCVTIMEO)pour timeouts.
