Mode datagramme

Nous allons tout d'abord voir, dans ce document, comment mettre en ?uvre un dialogue entre un client et un serveur en mode datagramme. Le sch?ma ci-dessous illustre les diff?rentes ?tapes que doivent accomplir un serveur (? droite) et un client (? gauche) pour pouvoir ?changer des donn?es en utilisant le protocole UDP. 

?tape 0 : biblioth?ques ? inclure

Pour utiliser les fonctions de la biblioth?que socket, il est n?cessaire d'importer une ou plusieurs biblioth?ques de fonctions qui contiennent les primitives que nous utiliserons ci-dessous. 

En Langage C

#include
#include  
#include

En Langage Java

import java.net.*;
import java.io.*;

En Langage Python

import socket

 Vous pourrez avoir besoin d'inclure d'autres biblioth?ques, notamment stdio.h et string.h en langage C, pour afficher et manipuler les r?sultats.

?tape 1 : cr?ation des descripteurs de la communication

La premi?re ?tape ? r?aliser, aussi bien par le serveur que par le client, est de cr?er une structure ou un objet qui va identifier la communication pour y faire r?f?rence par la suite. Un programme peut ouvrir de multiples connexions simultan?ment et il est, par cons?quent, n?cessaire d'?tre capable de les distinguer. 

En langage C et en Python, nous devrons faire appel ? la fonction socket qui renvoie un nombre entier qui servira d'identifiant de la communication. Cette fonction prend plusieurs arguments : le premier est le type de socket (PF_INET signifie que l'on souhaite cr?er un canal de communication TCP/IP et SOCK_DGRAM que l'on souhaite une communication en mode datagramme). En Java, on cr?e un objet appartenant ? la classe DatagramSocket qui est directement configur? de la bonne mani?re.  

En Langage C

int s = socket (PF_INET, SOCK_DGRAM, 0);

En Langage Java

DatagramSocket snew DatagramSocket();

En Langage Python

s = socket.socket (socket.AF_INET, socket.SOCK_DGRAM)

Une fois cette ?tape r?alis?e, la variable s nous permettra de faire r?f?rence au canal de communication que l'on aura cr??. C'est cette variable s que l'on va passer aux diff?rentes fonctions pour mettre en ?uvre les ?tapes de notre communication.

?TAPE 2 : r?servation du port (cot? serveur seul)

Le serveur, avant de pouvoir accepter des communications, devra demander au syst?me d'exploitation de lui transmettre tous les datagrammes qui lui parviendront sur le port de communication choisi. Pour cela, il faudra r?server ce port aupr?s du syst?me. Il est aussi possible de limiter l'attente ? une adresse IP lorsque l'on est sur une machine en poss?dant plusieurs. Cette ?tape, n?cessaire, passe par une fonction g?n?ralement appel?e bind et sp?cifique au serveur. Les param?tres de cette fonction, selon les langages, peuvent lui ?tre pass?s directement (Python) ou par l'interm?diaire d'une structure (C) ou d'un objet (Java).  

En Langage C

// Structure contenant l'adresse et le port sur lesquels ?couter
//     Type d'adresse ; AF_INET = IPv4
//     Adresse du r?cepteur - INADDR_ANY = n'importe quelle interface 
//     Port sur lequel ?couter
struct sockaddr_in myAddress;
myAddress.sin_family      = AF_INET;
myAddress.sin_addr.s_addr = htonl(INADDR_ANY);
myAddress.sin_port        = htons(12345);

// Enregistrement au niveau de l'OS
//     Param?tre 1 : descripteur de connexion
//     Param?tre 2 & 3 : adresse et taille de l'adresse
bind(s, (struct sockaddr *)&myAddress, sizeof(myAddress));

En Langage Java

// Objet repr?sentant l'adresse et le num?ro de port sur lesquels ?couter
//     Param?tre 1 : Adresse IP sur laquelle ?couter (null pour toutes)
//     Param?tre 2 : port sur lequel ?couter
InetSocketAddress myAddress = new InetSocketAddress((InetAddress)null, 12345);

// Enregistrement au niveau de l'OS
s.bind(myAddress);

En Langage Python

myAddress = ''         # ?couter sur toutes les interfaces r?seau
myPort    = 12345         # Port sur lequel ?couter
s.bind((myAddressmyPort))

Si l'appel ? bind r?ussit, le serveur est maintenant pr?t ? recevoir les datagrammes entrants.

?tape 3 : Le client envoie un datagramme au serveur

D?s que le serveur est pr?t ? recevoir les datagrammes, le client peut lui envoyer un message en appelant directement la fonction d'envoi : send ou sendto selon les langages. L'appel ? cette fonction et notamment ses param?tres est assez diff?rent selon les langages. Cependant, elle a besoin au minimum qu'on lui sp?cifie le message ? envoyer (une cha?ne de caract?res contenue dans la variable message dans nos exemples) et l'identit? de l'application r?ceptrice. Cette identit?, comme nous l'avons vu dans les vid?os, est compos?e de l'adresse de la machine h?bergeant l'application serveur, ainsi que du port qui a ?t? r?serv? par cette application.

Dans les exemples ci-dessous, on commence par r?cup?rer l'adresse IP du serveur situ? sur la machine locale (localhost), on pr?pare ensuite (si n?cessaire) une structure contenant l'identification du serveur (adresse IP et num?ro de port notamment). On pr?pare le message ? envoyer, puis on l'envoie au moyen de la fonction idoine. 

En Langage C

// Interrogation du DNS pour obtenir l'adresse IP de la destination
struct hostent *destination = gethostbyname("localhost");
in_addr_t destIPAddr = *((in_addr_t *)(destination->h_addr));

// structure repr?sentant l'adresse (+ num?ro de port) de destination
struct sockaddr_in destAddress;
destAddress.sin_family      = AF_INET;
destAddress.sin_addr.s_addr = destIPAddr;
destAddress.sin_port        = htons(12345);

// Pr?paration du message ? envoyer
char message[] = "Hello World\n";

// Envoi effectif du message
//     Param?tre 1 : identificateur de socket
//     Param?tres 2 & 3 : message & longueur du message
//     Param?tre 4 : drapeaux pour transmissions particuli?res
//     Param?tres 5 & 6 : adresse destination et taille de la structure
sendto(s, message ,strlen(message), 0, (struct sockaddr *)&destAddress, sizeof(destAddress));

En Langage Java

// Interrogation du DNS pour obtenir l'adresse IP de la destination
InetAddress destination = InetAddress.getByName("localhost");

// Objet repr?sentant l'adresse
//     Param?tre. 1 : adresse IP
//     Param?tre 2 : num?ro de port
InetSocketAddress destIPAddr=new InetSocketAddress(destination, 12345);

// Pr?paration du message ? envoyer
String message = "Hello World\n";
byte[] payload = message.getBytes();
DatagramPacket packet = new DatagramPacket(payload, payload.length, destIPAddr);

// Envoi effectif du message
s.send(packet);

En Langage Python

destIPAddr  = "localhost"
destPort    = 12345
message = "Hello, World\n"

s.sendto(message, (destIPAddrdestPort))

?tape 3 bis : Le serveur re?oit le datagramme du client

Du cot? du serveur, on se pr?parera ? recevoir des donn?es provenant du client en allouant un peu de m?moire pour le tampon de r?ception, puis en appelant la fonction recvfrom, qui est bloquante. Cela veut dire que l'ex?cution du programme serveur s'arr?tera ? cette ligne en attendant qu'un message parvienne ? notre application. 

Une fois que le serveur aura re?u un datagramme, il pourra utiliser le contenu du message et il disposera aussi de l'adresse de l'?metteur qui sera stock?e dans une structure qu'il aura pr?alablement allou?e si n?cessaire. Cela permettra alors au serveur d'envoyer une r?ponse au client de la m?me mani?re. 

En Langage C

// Tampon de r?ception
char message[1024];
int nbCars;

// Descripteur pour stocker l'adresse de l'?metteur
struct sockaddr_in sourceAddr;
socklen_t length = sizeof(sourceAddr);

// R?ception effective (bloquante) du message
//     Param?tre 1 : socket
//    Param?tres 2 & 3 : tampon de r?ception et taille de ce tampon
//    Param?tre 4 : drapeaux (inutilis? ici)


//    Param?tres 5 & 6 : adresse source & taille de l'adresse
nbCars = recvfrom (s, message, 1024, 0, (struct sockaddr *)&sourceAddr, &length);

En Langage Java

//Tampon de r?ception

byte[] message = new byte[1024]; 

// R?ception effective (bloquante) du message
DatagramPacket packet = new DatagramPacket(message, message.length);
s.receive(packet);

// R?cup?ration de l'adresse de l'?metteur
InetSocketAddress sourceAddr =(InetSocketAddress)packet.getSocketAddress();

En Langage Python

# R?ception, taille du tampon = 1024 octets
message, sourceAddr = s.recvfrom(1024)

Fin de la communication

UDP fonctionnant en mode datagramme, la communication s'arr?te d?s que les deux correspondants ne transmettent aucune donn?e. Il n'y a donc pas de fonction r?elle pour mettre fin ? la communication, mais il est toutefois n?cessaire d'appeler une fonction pour lib?rer les ressources (m?moire etc.) qui ont ?t? r?serv?es par le syst?me lorsque l'on n'a plus l'usage du canal de communication. Cette op?ration est r?alis?e au moyen d'une fonction nomm?e close.

En Langage C

close(s);

En Langage Java

s.close();

En Langage Python

s.close()

No module Published on Offcanvas position