(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/>