Puis-je ignorer l'ordre des octets en toute sécurité dans le réseau?

24

Je développe une application serveur-client où le client fonctionnera sous Windows et le serveur probablement sous Linux. Peut-être que je porterai plus tard le client sur Mac et Linux, mais pas encore.

Tous les ordinateurs personnels fonctionnent de nos jours sur le petit-boutien. J'ai googlé un moment, mais je n'ai pas vraiment pu trouver une liste d'appareils fonctionnant sur big-endian. Pour autant que je sache, certaines puces Motorola utilisent encore du big-endian et peut-être certains téléphones (je ne prévois pas de porter l'application sur les smartphones, donc cela n'a pas d'importance pour moi). Alors, pourquoi réorganiserais-je les octets de chaque entier, chaque court, chaque flottant, double, etc., pour la lecture et l' écriture , alors que je sais déjà que le serveur et le client s'exécutent sur little-endian?

C'est juste un travail inutile à faire. Donc, ma question est: puis-je ignorer l'endianité en toute sécurité et envoyer simplement des données de petit endian? Quels sont les inconvénients?

tkausl
la source
4
Comment les machines sauront-elles si elles reçoivent des données de petit endian au lieu des données de big-endian habituelles / standard?
Ixrec
2
Vous devez faire la distinction entre les métadonnées requises par le protocole réseau et la charge utile qui n'est qu'un tas d'octets non interprétés pour tout le monde sauf votre code. J'espère que vous ne roulez pas votre propre pile réseau. Par conséquent, je suppose que la question concerne uniquement la charge utile, n'est-ce pas?
2
@delnan oui, je ne parle que de la charge utile. Je parlerai bien sûr toujours dans l' ordre des octets réseau à la pile réseau elle-même.
tkausl
3
Juste une pensée sur le côté: est-ce vraiment nécessaire pour vous de travailler à un niveau d'abstraction où l'endianisme est une préoccupation? Il pourrait être utile d'envisager d'utiliser des protocoles pour lesquels il existe des bibliothèques appropriées qui encapsulent tout ce "gâchis" de bas niveau. Ensuite, vous avez également l'avantage supplémentaire que l'ajout de nouveaux clients peut être fait beaucoup plus facilement.
godfatherofpolka
1
@tkausl Juste deux autres réflexions sur le côté: En règle générale, les E / S sont extrêmement lentes par rapport aux calculs, de sorte que toute surcharge introduite en travaillant à un niveau d'abstraction plus élevé est très probablement négligeable. Il peut même arriver que certaines bibliothèques surpassent les implémentations manuelles en raison de la mise en commun intelligente des ressources et de la gestion asynchrone, etc. Donc, j'évaluerais d'abord soigneusement les solutions existantes. En outre, compte tenu de votre description, je voudrais également passer quelques réflexions sur l'évolutivité plutôt que sur les performances, ici, vous pourriez à nouveau bénéficier de l'utilisation de protocoles de niveau supérieur.
godfatherofpolka

Réponses:

29

... pourquoi devrais-je réorganiser les octets ... alors que je sais déjà que le serveur et le client fonctionnent sur le petit endian? C'est juste un travail inutile à faire.

Ce n'est inutile que si vous pouvez garantir que votre code fonctionnera toujours sur des architectures peu endiennes. Si vous avez l'intention qu'il ait une longue durée de vie, cela vaut la peine de faire l'effort supplémentaire pour éviter de perturber le code éprouvé dans une décennie à partir de ce moment où une architecture big-endian est devenue le "in" et que vous trouvez que c'est un bon marché pour ton application.

Il existe un ordre d'octets standard du réseau. C'est du big-endian, mais rien ne dit que vous devez le respecter lors de la conception de votre protocole. Si vous savez à l'avance que la majorité des systèmes exécutant votre code seront peu endiens et que les performances sont critiques, déclarez que le "tkausl standard byte ordering" et allez-y. Là où vous appelez normalement htons()pour mettre les choses dans l'ordre dont vous avez besoin, écrivez une macro appelée htots()qui se compile conditionnellement sur rien sur les architectures little-endian et fait le réarrangement sur big-endian.

Maintenir le code pour effectuer les conversions entrantes et sortantes n'est pas vraiment un gros effort. Si vous avez un très grand nombre de messages, trouvez un moyen de les exprimer et écrivez un programme pour générer les conversions entrantes et sortantes.

Blrfl
la source
10
Le libellé when designing your protocolest important, car il dit également implicitement que cette option n'existe que lors de la conception d'un nouveau protocole et non lors de la mise en œuvre d'un protocole existant. Et mentionner la nécessité d'une htots(et vraiment d'une famille entière de fonctions), indique également clairement que le choix d'un ordre d'octets différent n'est pas quelque chose que l'on fait pour rendre le code plus simple, mais cela pourrait le rendre légèrement plus rapide.
kasperd
4
Il y a ces jours -ci (non standard mais très communs) fonctions htole32(), htole16(), le16toh(), etc., les fonctions disponibles. Le fichier à inclure pour les faire déclarer est malheureusement encore moins standard: <endian.h>ou <sys/types.h>selon la plateforme.
torek
Cette réponse est correcte, mais je pense que l'hypothèse selon laquelle la performance peut être critique dans le cas donné est très probablement une hypothèse erronée, basée davantage sur la superstition que sur des faits.
Doc Brown
1
@DocBrown: J'aime toujours souligner que le protocole X prend en charge la sélection de votre propre ordre d'octets depuis 30 ans, et aussi restreint que les ressources étaient à l'époque, personne ne s'est jamais plaint que c'était un problème.
Blrfl
7

C'est ton protocole.

Vous ne pouvez pas l'ignorer en toute sécurité. Mais vous pouvez l'étiqueter en toute sécurité. Vous contrôlez le client et le serveur. Vous contrôlez le protocole. N'est-il pas logique de ne pas se soucier de savoir si c'est du big-endian ou du little-endian tant que vous savez si les deux parties sont d'accord?

Cela signifie des frais généraux. Maintenant, vous devez marquer votre endianité d'une manière ou d'une autre. Faites cela, et je peux le lire sur n'importe quoi.

Si vous ne voulez pas de surcharge de données et que votre CPU s'ennuie et cherche quelque chose à faire, alors conformez-vous .

candied_orange
la source
6

Donc, ma question est: puis-je ignorer en toute sécurité l'endianess et envoyer simplement des données little-endian?

Il y a deux interprétations de cela:

  • Si vous concevez vos applications / protocoles pour toujours envoyer 1 little-endian, alors vous n'ignorez pas l'endianess.

  • Si vous concevez vos applications / protocoles pour envoyer / recevoir quel que soit l'endianess natif, alors ils fonctionneront tant que vous exécuterez vos applications sur des plates-formes avec la même endianess native.

    Est-ce "sûr" 2 ? A vous de juger! Mais il existe certainement des plates-formes matérielles communes qui utilisent le petit-boutien, le gros-boutien ou ... le bi-boutien.

    Référence:

Quels sont les inconvénients?

L'inconvénient évident d'ignorer l'endianess est que si vous / vos utilisateurs devez exécuter vos applications / protocoles entre des plates-formes ayant une endianess native différente, alors vous avez un problème. Les applications s'arrêteront et vous devrez les modifier pour résoudre le problème. Et gérer les problèmes de compatibilité des versions, etc.

De toute évidence, la plupart des plates-formes de génération actuelles sont nativement peu endiennes, mais 1) certaines ne le sont pas et 2) nous ne pouvons que deviner ce qui se passera à l'avenir.


1 - Toujours ... y compris sur des plateformes natives big-endian.

2 - En effet, que signifie «sûr»? Si vous nous demandez de prédire l'orientation future des plates-formes matérielles ... Je crains que ce ne soit pas objectivement responsable.

Stephen C
la source
3

L'endianisme n'est pas la seule considération. Il y a la taille des entiers, il y a un paquet de structures que vous voudrez peut-être envoyer ou recevoir, etc.

Vous pouvez ignorer tout cela. Personne ne peut te forcer. D'un autre côté, le moyen sûr et fiable est de documenter un format externe, puis d'écrire du code qui lira ou écrit correctement le format externe, quels que soient votre processeur, votre langage de programmation et l'implémentation de votre langage de programmation.

Ce n'est généralement pas beaucoup de code. Mais cela a un énorme avantage: les personnes qui lisent votre code ne soupçonneront pas que vous êtes ignorant, ne savent rien sur l'échange de données externes et écrivent du code qui ne peut généralement pas faire confiance.

gnasher729
la source
3

La pile de mise en réseau BSD standard en C a la fonctionnalité hton/ ntoh( network-to-host/ host-to-network) qui s'étend aux no-ops sur les machines natives du réseau (big endian). Vous auriez besoin de vos propres homologues pour ceux-ci pour le scénario dans lequel l'ordre des octets natif du réseau est peu endian.

C'est la manière robuste de le faire.

Ce ne serait pas conventionnel, mais je n'y vois rien de mal. Les ordinateurs en réseau obtiennent toujours des flux d'octets et ils doivent s'entendre sur des protocoles sur la façon d'interpréter ces octets. Cela n'en fait qu'une partie.

PSkocik
la source
3

Différents protocoles utilisés pour transmettre des données entre serveurs utilisent de petits nombres endiens:

  1. BSON
  2. Tampons de protocole
  3. Capn Proto

Voir https://en.wikipedia.org/wiki/Comparison_of_data_serialization_formats , pour plus de détails sur les différents formats dont certains ont des nombres en petit bout et certains ont des nombres en gros.

Il n'y a absolument rien de mal à utiliser un protocole basé sur de petits nombres endiens. Une grande machine endienne est tout aussi capable de lire de petits nombres endiens qu'une petite machine endienne peut lire de grands nombres endiens. Beaucoup de gens l'ont fait spécifiquement pour éviter le coût de calcul supplémentaire du décodage des nombres big-endian sur les petites machines endian.

Si vous construisez votre protocole sur l'un de ces protocoles existants, vous n'avez même pas à vous soucier du problème vous-même, il est déjà pris en charge. Lorsque vous décidez d'exécuter votre code sur une plate-forme big-endian, les bibliothèques qui implémentent ces protocoles se chargeront automatiquement de s'assurer que vous décodez les valeurs correctement.

Winston Ewert
la source
2

Un exemple d'un grand système endian est le MIPS utilisé dans les routeurs. ARM et MIPS sont commutables par endian, mais souvent MIPS est un gros endian car il facilite le matériel réseau (la partie la plus importante d'un mot est la partie que vous recevez en premier et peut prendre une décision de routage avant d'avoir reçu le reste de le mot plutôt que d'avoir à mettre le mot entier en mémoire tampon).

Cela dépend donc de ce que vous entendez par `` Linux '', mais si vous souhaitez exécuter votre application serveur sur un système plus petit comme un routeur exécutant OpenWRT, vous devrez peut-être envisager un support endian important.

Comme d'habitude, faire des hypothèses simplificatrices est une optimisation parfaitement sensée jusqu'à ce que vous frappiez quelque chose qui ne correspond pas aux hypothèses. Vous seul pouvez dire à quel point il serait douloureux de les dérouler si jamais vous rencontriez un tel problème.

user1908704
la source
0

Je ne pense pas que les réponses soient assez précises. Selon Wikipedia, l' endianité est l'ordre des octets comprenant un mot.

Permet de prendre 4 octets et de les interpréter comme un entier. Dans un petit système endian, les octets seront interprétés de droite à gauche, et vice-versa sur un grand système endian. De toute évidence, il est important de s'entendre sur la fin de l'interprétation d'un int.

Permet de zoomer un peu sur les protocoles réseau modernes qui pourraient utiliser json ou xml. Aucun de ces formats ne transférera un entier sous forme de 4 octets. Ils transfèrent les données sous forme de texte qui sera analysé en tant qu'intérieur sur le côté récepteur.

Donc, à la fin, l'endianité n'a pas d'importance lors de l'utilisation de json ou xml. Nous devons encore utiliser big endian pour les en-têtes tcp, c'est pourquoi il est appelé ordre des octets du réseau, mais la plupart des programmeurs n'ont pas besoin de jouer avec ceux-ci quotidiennement.

L'encodage le plus largement utilisé aujourd'hui est utf-8 qui est également immunisé contre les problèmes d'endianisme .

Je dirais donc oui. Il est sûr d'ignorer l'endianité lors de l'utilisation de formats basés sur du texte transférés à l'aide d'utf-8.

Esben Skov Pedersen
la source
deux votes négatifs et aucun commentaire. Génial.
Esben Skov Pedersen
1
Je n'étais pas le downvoter mais cette réponse semble ignorer / rejeter une question parfaitement valable. Ce n'est pas parce que certains protocoles sont basés sur du texte que tous les protocoles devraient l'être.
Peter Green
2
J'ai voté contre cela parce que cela touche le fait que le format de la charge utile n'a rien à voir avec les protocoles sous-jacents. Certaines personnes adorent creuser des problèmes inventés.
Zdenek
0

Les grands systèmes endiens semblent en voie de disparition. Beaucoup des unix traditionnels utilisaient du big endian mais ils sont en déclin depuis des années en faveur de linux sur x86.

le bras est bi-endien mais la variante big endian semble être rarement vue.

mips existe dans les deux variantes. Afaict la variante big endian est principalement observée sur les applications de mise en réseau (pour des raisons historiques, les protocoles Internet utilisent généralement le big endian).

ppc était traditionnellement un gros endian avec certaines parties prenant en charge les deux endians mais IBM semble maintenant pousser le petit mode endian pour le ppc 64 bits (ils ont récemment poussé les ports ppc64el dans Debian et Ubuntu).

sparc est normalement gros endian mais semble encore être en déclin.

Si vous implémentez un protocole existant, vous devez évidemment suivre ses spécifications. Si vous voulez que l'IETF bénisse votre nouveau protocole, le big endian sera probablement plus facile, car c'est ce qu'ils utilisent déjà dans leurs protocoles existants, mais IMO pour une nouvelle conception de protocole "greenfield", peu endian est le chemin à parcourir.

Vous pouvez soit mettre des macros depuis le début qui seront sans opération sur les petits systèmes endiens, soit vous ne pouvez pas déranger jusqu'à / à moins que vous ayez besoin de porter sur un grand système endien.

Peter Green
la source