(Courriels de diversion: <charites@banjos-ruinant.com> <plaignaient@chancre-appelles.com> <recycleraient@transcrirai-surgeles.com> <rebiffa@validerait-remmenez.com> <concourant@dissimuleriez-imaginerions.com> <degouts@viroles-gitane.com> <usinera@retraduisiez-constatent.com> <sous-estimerez@jouissions-reorganisez.com> <jalonnez@accentuez-subtile.com> <etable@mêlaient-annoterez.com> )


Le 22 Déc, j'écrivais :
> Le 21 Déc, Frank écrit :
> 
>>   to.sin_port=6667;
> 
>   to.sin_port = htons(6667);

  Pourquoi ? Mais pourquoi tant de haine ?

  Imaginons que je travaille en 32 bits, avec des caractères de 8 bits,
  et que la machine sache adresser des caractères individuels.

  Si je définis une chaîne de 4 caractères (avec les caractères codés en
ASCII) : abcd (donc 0x61, 0x62, 0x63, 0x64), avec le « a » à l'adresse
machine la plus basse.

  Imaginons que je définisse un entier non signé de 32 bits dont
l'adresse de départ commence à la même adresse que la chaîne précédente.

  Quelle est la valeur de cet entier ?

  Il n'y a pas de réponse unique. J'ai quatre caractères à placer dans
quatre emplacements mémoire. Je peux aussi bien avoir comme valeur
0x61626364 que 0x64636261 ou tout autre arrangement exotique.

  En fait, la valeur que j'obtiens dépend du processeur que j'utilise.
Chaque processeur a sa manière à lui d'interpréter une suite d'octets
lue en mémoire comme un nombre entier.

  Si vous pensez, à ce stade, que ça doit poser des problèmes quand on
échange des données en environnement hétérogène, vous avez raison.

  C'est bien pour ça que des conventions minimales ont été développées.
Ces conventions conviennent de définir un ordre des octets sur le
réseau. Rien de magique là-dedans : la convention s'arrête à ce qui est
explicitement défini : certaines fonctions d'accès au réseau
interprètent l'ordre des octets d'un multi-octet d'une certaine façon,
fixe, quel que soit le processeur (qui est, lui, libre d'interpréter
cette ordre comme il veut).

  Dans la pratique, on suppose que le réseau sait échanger des octets.
Le problème ne se pose donc que quand on souhaite échanger des trucs qui
font plus d'un octet : dans la pratique 2 octets (numéros de ports) ou 4
(adresse IP [v4]).

  Au niveau de l'API C, c'est simple : tout ce qu'on donne aux routines
qui ont trait au réseau (bind, connect, etc) doît être dans l'ordre du
réseau. Tout ce qu'on reçoit de ces mêmes routines (getsrvbyname,
gethostbyname, etc) est dans l'ordre du réseau.

  Il faut considérer qu'il y a une barrière conceptuelle entre l'ordre
du réseau et l'ordre du processeur, même quand on travaille sur un
processeur pour lequel ces ordres ont identiques (SPARC par exemple).

  Il existe quatre fonctions de conversion entre ces ordres : deux dans
chaque sens, pour chaque taille en octets (2 ou 4).

  htonX : hôte (processeur) vers réseau (host to network) ;
  ntohX : réseau vers hôte (processeur) (network to host).

  « X » peut être « s » (short : 2 octets) ou « l » (long : 4 octets).

  Ainsi, un ensemble d'octets obtenus d'un fonction réseau
(gethostbyname par exemple) ne peut pas être manipulé par un programme :
la seule chose qu'il peut en faire est la recopier ou la passr à ntohX.

  De manière symétrique, si un programme peut manipuler un nombre
(scanf, atoi, ou un littéral numérique comme 6667), il ne peut pas le
donner tel quel à une fonction réseau : il doit d'abord le transformer
en un suite d'octets représentant le même nombre dans l'ordre réseau, à
l'aide d'un htonX.

  En résumé :
   - tout ce que je donne à une fonction réseau est une suite
     d'octets représentant un nombre en ordre réseau ;
   - tout ce que je reçois d'une fonction réseau est
     un suite d'octets repérsentant un nombre dans l'ordre réseau ;
   _ un littéral numérique (6667), un nombre sur lequel je peux
     faire + 1 ou * 2, un nombre obtenu par atoi ou scanf sont des
     nombres représentés dans l'ordre de l'hôte (sinon je ne pourrais
     pas faire d'opérations dessus) ;
   - je transforme les nombres sur lequels je peux faire des opérations
     en nombres dans l'ordre réseau en utilisant les fonctions htons et
     htonl ;
   - je transforme les retours des fonctions réseau en nombres
     manipulables en utilisant les fonctions ntohs et ntohl.

  Attention : les suites d'octets représentant des nombres dans l'ordre
réseau ne sont retornées et acceptées que par les fonctions de contrôle
de le connexion : l'échange de données (par read et write) n'obéit pas à
cette distinction : vous en êtes entièrement responsables.

  Au cas où je ne serais pas assez clair : il vous faut définir en ce
cas un protocole de sérialisation (structure de données multi-octets ->
séquence linéaire d'octets) et l'opération inverse (lecture d'une
séquence d'octet -> construction de la strucure de données).

-- 
Marc Thirion              | Ramonville Saint-Agne, France
Un Travail pour Chacun    : http://www.multimania.com/untravailchacun/
Marc.Thirion@ISOscope.com : http://www.ISOscope.com/Pérennité des logiciels et des systèmes



---------------------------------------------------------------------
Aide sur la liste: <URL:mailto:linux-31-help@savage.iut-blagnac.fr>Le CULTe sur le web: <URL:http://www.CULTe.org/>