Groupe pour la Promotion de GNU/Linux en Royans Vercors
Accueil du site > Articles techniques > Applications réseau avec GNet

Applications réseau avec GNet

lundi 15 juin 2009, par Zedraken

Introduction

L’écriture d’applications réseau nécessite la manipulation de concepts très basiques comme les sockets par exemple, de jongler avec les arcanes des couches ISO, bref, d’utiliser des concepts qu’il est intéressant de comprendre, mais qui deviennent assez vite rébarbatifs.

Il est plus intéressant d’essayer d’utiliser des wrappers comme la libgnet qui est une librairie s’appuyant sur la GLib et fournissant tout un jeu de fonctions permettant l’écriture d’application réseau.

Il existe de nombreuses librairies réalisant cet objectif. Parmi celles-ci, on peut citer :
- SDL_net
- PLib net
- Raknet (http://www.jenkinssoftware.com/)
- libpcap

Cet article se focalise sur l’utilisation de la libgnet par l’implémentation d’un serveur de voix sur IP (VoIP). Cet exemple sera abondamment illustré car même si la documentation officielle de GNet détaille toutes les fonctions disponibles, il n’est pas forcément évident de savoir comment ni dans quel ordre les utiliser. Et pour bien les utiliser, il est nécessaire de bien comprendre comment fonctionnent les connexions TCP/IP et UDP/IP.

Comprendre les connexions TCP et UDP

Les connexions réseau peuvent utiliser le protocole TCP (Transfer Control Protocol) ou UDP (User Datagram Protocol), ou les deux en même temps selon les besoins ou les contraintes.

Dans le modèle OSI, le protocole TCP est situé au-dessus du protocole UDP, ce qui signifie qu’il est plus complexe mais en revanche il est plus sûr. En effet, le protocole TCP garantit l’intégrité des données reçues ainsi que leur ordre d’arrivée (qui correspond à l’ordre dans lequel elles ont été envoyées). Cette qualité de transmission se paie au prix d’un plus grand contrôle et d’une mécanique interne à TCP qui permet de remettre les données dans le bon ordre avant de les présenter à l’applicatif qui en a besoin.

Malheureusement, ce protocole se prête très mal à la transmission de données présentant un aspect temps réel, comme par exemple des échantillons sonores correspondant à de la voix. En effet, si un paquet corrompu arrive, le protocole TCP va entrer dans une phase dans laquelle il va redemander l’échantillon à l’émetteur, et ce jusqu’à ce que l’échantillon non corrompu lui arrive, ou jusqu’à expiration d’un timeout. Le problème qui se pose alors est que si l’échantillon non corrompu finit par arriver correctement, sa pertinence temporelle n’est plus valable. On perd donc l’aspect « temps réel ». Dans ce cas, il vaut mieux perdre purement et simplement cet échantillon mais conserver la dynamique « temps réel ». Si on considère qu’un échantillon transporté par un paquet représente 20 milli-secondes de voix, alors on aura un trou de 20 milli-secondes. Dans la majorité des cas, c’est une contrainte acceptable.

On dit souvent que le protocole TCP est orienté connexion. Cela signifie en fait qu’un serveur TCP se met à l’écoute d’une connexion entrante provenant d’un client avant de se mettre réellement à l’écoute des données arrivant de ce client. Tant qu’une connexion (au sens TCP) n’a pas été établie entre le serveur et le client, aucune donnée utile ne peut être transmise. Dans ce protocole, une session de connexion est négociée avant toute chose.

Le schéma suivant présente le modèle en couches TCP/IP, inspiré du modèle OSI dont il représente une simplification.

Le protocole TCP n’étant pas adapté pour ce que nous voulons faire, on va regarder du côté du protocole UDP. Ce protocole est beaucoup plus simple. En premier lieu, il n’y a pas de négociation de connexion. Un client peut directement envoyer des données au serveur sans qu’il y ait de connexion préalable. Si des données corrompues arrivent, elles ne sont pas redemandées, donc on peut potentiellement perdre ces données mais on ne perd pas le temps lié à leur retransmission. Un autre aspect qui contribue à rendre ce protocole "rapide" est que si deux paquets arrivent dans le mauvais ordre (par rapport à l’ordre dans lequel ils ont été émis), ils ne sont pas remis dans le bon ordre et sont présentés tels quels à l’applicatif. Cela peut représenter un inconvénient mais on va voir qu’il est possible, dans une certaine mesure, de s’affranchir de cet inconvénient.

En conclusion, le protocole UDP est nettement plus adapté à notre mini-projet de serveur de VoIP. Heureusement pour nous, la librairie libgnet met à notre disposition un jeu de fonctions permettant d’exploiter ce protocole sans être obligé de rentrer dans les détails de son implémentation.

Serveur de VoIP

Le serveur sera très simple. Il sera chargé de recevoir les données représentant les échantillons sonores provenant des différents clients et de les transférer vers les autres clients, comme illustré dans le schéma suivant :

Afin de limiter la consommation de la bande passante, les données audio seront compressées en utilisant le codec Speex au travers de l’utilisation de la librairie libre libSpeex (voir http://www.speex.org/). De plus, le niveau de qualité sera volontairement dégradé car l’objectif est de simuler des liaisons radio en mono.

Le serveur n’utilisera que la libgnet et sera développé uniquement sous Linux. Les clients utiliseront les librairies suivantes :
- libgnet (pour la partie réseau)
- Speex (pour le codec audio)
- OpenAL (pour la gestion du microphone et des haut-parleurs)

Les clients tourneront sous Linux et sous Windows.

Concernant le code source en langage C, cet article n’en montrera que les parties essentielles. L’ensemble du code source pourra être téléchargé et recompilé, de même que les version binaires seront également disponibles.

Le serveur

Le client


Article en cours de rédaction...

SPIP | squelette | | Plan du site | Suivre la vie du site RSS 2.0