Au niveau du serveur, l'objectif est aussi
d'ouvrir un nouveau socket ; ce qui revient aussi à
ouvrir un canal de communication réseau avec la fonction
socket.
int listenSocket;
<snipped/>
listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (listenSocket < 0) {
cerr << "cannot create listen socket";
exit(1);
}
Cette étape ne présentant aucune différence avec le niveau client, on relie le numéro de socket avec le numéro de port choisi.
int listenSocket; struct sockaddr_in serverAddress; <snipped/> serverAddress.sin_family = AF_INET; serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(listenPort); if (bind(listenSocket
, (struct sockaddr *) &serverAddress, sizeof(serverAddress)
) < 0) { cerr << "cannot bind socket"; exit(1); }
|
|
|
|
|
|
|
|
Une fois la liaison établie, le programme attend les datagrammes provenant du client.
int listenSocket; struct sockaddr_in clientAddress; char line[(MAX_MSG+1)]; <snipped/> listen(listenSocket, 5); <snipped/> if (recvfrom(listenSocket, line, MAX_MSG
, 0, (struct sockaddr *) &clientAddress, &clientAddressLength) < 0) { cerr << " I/O Problem"; exit(1); }
|
La fonction |
|
|
Les paramètres |
Enfin, les émissions de datagramme du serveur vers le client utilisent
exactement les mêmes appels à la fonction sendto que les
émissions du client vers le serveur.
Code du programme udp-server.cc :
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>
#include <iostream>
#define MAX_LINE 100
// 3 caractères pour les codes ASCII 'cr', 'lf' et '\0'
#define LINE_ARRAY_SIZE (MAX_LINE+3)
using namespace std;
int main()
{
int listenSocket, i;
unsigned short int listenPort;
socklen_t clientAddressLength;
struct sockaddr_in clientAddress, serverAddress;
char buf[LINE_ARRAY_SIZE];
memset(buf, 0x0, LINE_ARRAY_SIZE); // Mise à zéro du tampon
cout << "Enter port number to listen on (between 1500 and 65000): ";
cin >> listenPort;
// Création de socket en écoute et attente des requêtes des clients
listenSocket = socket(AF_INET, SOCK_DGRAM, 0);
if (listenSocket < 0) {
cerr << "cannot create listen socket";
exit(1);
}
// Connexion du socket au port en écoute.
// On commence par initialiser les champs de la structure serverAddress puis
// on appelle bind(). Les fonctions htonl() et htons() convertissent
// respectivement les entiers longs et les entiers courts du rangement hôte
// (sur x86 on trouve l'octet de poids faible en premier) vers le rangement
// réseau (octet de poids fort en premier).
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = htonl(INADDR_ANY);
serverAddress.sin_port = htons(listenPort);
if (bind(listenSocket,
(struct sockaddr *) &serverAddress,
sizeof(serverAddress)) < 0) {
cerr << "cannot bind socket";
exit(1);
}
// Attente des requêtes clients.
// C'est un appel non-bloquant ; c'est-à-dire qu'il enregistre ce programme
// auprès du système comme devant attendre des connexions sur ce socket avec
// cette tâche. Puis, l'exécution se poursuit.
listen(listenSocket, 5);
cout << "Waiting for request on port " << listenPort << "\n";
while (1) {
clientAddressLength = sizeof(clientAddress);
// Mise à zéro du tampon de façon à connaître le délimiteur
// de fin de chaîne.
memset(buf, 0x0, LINE_ARRAY_SIZE);
if (recvfrom(listenSocket, buf, LINE_ARRAY_SIZE, 0,
(struct sockaddr *) &clientAddress,
&clientAddressLength) < 0) {
cerr << " I/O Problem";
exit(1);
}
// Affichage de l'adresse IP du client.
cout << " from " << inet_ntoa(clientAddress.sin_addr);
// Affichage du numéro de port du client.
cout << ":" << ntohs(clientAddress.sin_port) << "\n";
// Affichage de la ligne reçue
cout << " Received: " << buf << "\n";
// Conversion de cette ligne en majuscules.
for (i = 0; buf[i] != '\0'; i++)
buf[i] = toupper(buf[i]);
// Renvoi de la ligne convertie au client.
if (sendto(listenSocket, buf, strlen(buf) + 1, 0,
(struct sockaddr *) &clientAddress,
sizeof(clientAddress)) < 0)
cerr << "Error: cannot send modified data";
}
}
Vous êtes ici :