Ne sin_addr.s_addr = INADDR_ANY; besoin htonl à tous?
Je suis tombé sur deux threads:
Prise avec recv-délai d'attente: Quel est le problème avec ce code?
Lecture /Écriture à une prise secteur à l'aide d'un flux de FICHIER en c
on utilise htonl
et l'autre n'a pas.
Qui est à droite?
- +1 pour essayer de faire la lumière sur une confusion de la zone: le top hit sur Google n'est même pas sûr: tech-archive.net/Archive/Development/... - le message lié dit (assez convaincante) que htonl n'est pas nécessaire pour ces constantes, alors le message de suivi retire de la déclaration, disant htonl est nécessaire!
- Ce n'est pas une confusion de la zone. Si vous connaissez la valeur numérique de INADDR_ANY, il est clair que
htonl()
ne fait rien pour le résultat, zéro dans les résultats de zéro; de même, pour INADDR_ALL, 0xFFFFFFFF àhtonl()
résultats dans 0xFFFFFFFF out. Cependant, INADDR_LOOPBACK est différent: il est spécifié dans l'ordre des octets de réseau comme 0x7F000001. Pour cette constante, l'utilisation dehtonl()
est nécessaire. - Vous pouvez lire (et downvote!) ma réponse ci-dessous. Je l'ai écrit avant @Mat mis à jour sa réponse pour dire que htonl doit être utilisé, après tout. Juste parce que vous dites cette zone ne crée pas de confusion à ne pas faire en sorte (et la preuve, c'est que un certain nombre de gens qui trouvent à confusion).
- Il est source de confusion dans la mesure où les gens n'ont pas établi leur base de connaissances dans le domaine. Si le programmeur ne peut pas lire de la sortie de
ifconfig
,netstat
,tcpdump
, puis ils vont être rien, mais confus. Si ils ont des connaissances de base de ce domaine, ils ne seront pas confus. - Le point est INADDR_ANY/INADDR_LOOPBACK ne pas avoir une valeur spécifiée. Il est clair sur votre machine, comment il fonctionne, mais qui pourrait ne pas être univerally vrai (ou peut - qui est ce que la question est à propos)
- Ma machine est probablement filaire à votre ordinateur ou à votre réseau sans fil hub. À un certain niveau, ils ne fonctionnent de la même, la manière spécifiée par l'IETF Rfc. C'est pas par hasard que les sockets Berkeley API traite les constantes de cette façon -, mais les avocats de l'encapsulation et d'abstraction suggère que nous prétendons, c'est une coïncidence.
- Les Rfc ne précise pas que INADDR_LOOPBACK devrait être 0x7F000001 ou, par exemple, 0x100007F.
- Sauf si vous pouvez penser à tous les cas où INADDR_LOOPBACK ne serait pas 127.0.0.1, je dirai qu'il sera toujours 0x7f000001.
Vous devez vous connecter pour publier un commentaire.
Depuis d'autres constantes comme
INADDR_LOOPBACK
sont dans l'ordre des octets de l'hôte, je pense que toutes les constantes dans cette famille devrait avoirhtonl
appliquées, y comprisINADDR_ANY
.(Note: j'ai écrit cette réponse alors que @Mat a été l'édition; sa réponse maintenant, il est également préférable d'être cohérent et de toujours utiliser
htonl
.)Justification
Il est un danger pour les futurs responsables de votre code si vous l'écrire comme ceci:
Si je passais en revue ce code, je le ferais immédiatement la question de savoir pourquoi l'une des constantes a
htonl
appliquée et l'autre pas. Et je voudrais signaler un bug, si oui ou non il m'est arrivé d'avoir des "connaissances" queINADDR_ANY
est toujours 0 si la conversion c'est un no-op.Le code que vous écrivez n'est pas seulement sur le fait d'avoir le bon comportement d'exécution, il devrait être aussi évident lorsque c'est possible et facile de croire qu'il est correct. Pour cette raison, vous ne devez pas foirer le
htonl
autour deINADDR_ANY
. Les trois raisons pour ne pas utiliserhtonl
que je peux voir sont:htonl
parce qu'ils savent qu'il ne fait rien (étant donné qu'ils connaissent la valeur de la constante par cœur).htonl
. Je pense que des gens qui se connaissent mais n'ont pas l'expertise avec son support Api, il est plus facile de maintenir le code si il est compatible. Je suis d'accord pour être en désaccord avec votre affirmation qu'il est préférable d'écrire du code qui n'est pas sympa pour les débutants.htonl
et des amis, donc il y aura zéro impact sur les performances.INADDR_ANY
est le "tout" adresse IPV4. Cette adresse est0.0.0.0
dans la notation par points, de sorte0x000000
en hexadécimal sur toute l'endianness. Passer au travers d'htonl
n'a aucun effet.Maintenant, si vous voulez interroger sur d'autres macro-constantes, regardez
INADDR_LOOPBACK
si elle est définie sur votre plate-forme. Les Chances sont qu'il sera une macro comme ceci:(à partir de
linux/in.h
, soit l'équivalent de la définition dans leswinsock.h
).Donc pour
INADDR_LOOPBACK
, unhtonl
est nécessaire.Pour des raisons de cohérence, il pourrait donc être préférable d'utiliser
htonl
dans tous les cas.htonl()
introduit un code de maintenance bug est naïf -- de toute évidence, vous n'avez pas fait tout sockets interface de programmation. Il n'y a aucune occasion d'un entretien nécessiterait de modifier un INADDR_ANY pour un INADDR_LOOPBACK, et il n'y a pas de personne qualifiée responsable de prises de code qui ne sait pas que INADDR_ANY est synonyme de zéro. Je dirais même mieux de ne pas muet vers le bas et d'inviter un grand responsable dans la source -- ils coûtent plus qu'ils ne bénéficient.N'est droit, dans le sens que les deux
INADDR_ANY
ethtonl
sont obsolètes, et conduire à des complexes, laid code qui ne fonctionne qu'avec IPv4. Commutateur à l'aide degetaddrinfo
pour l'ensemble de votre adresse de socket besoins de création:Remplacer
"1234"
avec votre numéro de port ou le nom du service.atoi
que d'utiliserhtons
, mais sinon, OK.AI_NUMERICSERV
est seulement nécessaire pour inhiber basée sur une chaîne de recherche dans le service. Si votre chaîne est un nombre de toute façon, il devrait être un no-op. Mais il ne pouvait pas faire de mal à la comprendre./etc/services
ou essayez d'abord deatoi
sur le paramètre?/etc/services
lorsque l'argument est numérique. Puis de nouveau la glibc ne cesse de me surprendre, de sorte que vous pouvez utiliserstrace
et vérifier que... 😉/etc/services
n'a pas été ouvert lorsque le service a été un nombre (comme dans votre réponse). Il a été ouvert quand le service a été un nom (comme "asp"). Ce fut à l'aide de la glibc 2.13 (la version stable actuelle).AI_NUMERICSERV
. La seule utilisation serait explicitement rejeter non numérique service de noms, mais vous pourriez tout aussi bien avoir rejeté plus tôt vous-même. Merci pour le contrôle.getaddrinfo
n'est pas une panacée, et que le plus simpleinet_pton
devrait être utilisé si possible - blog.powerdns.com/2014/05/21/...inet_pton
ne peut pas travailler, par exemple, avec les adresses lien-local nécessitant une identification de portée, sauf si vous ajoutez l'adresse de la famille-la logique spécifique sur le dessus de cela. Le blog vous est lié au sujet d'un stupide glibc bug qui a heureusement été signalé et corrigé. Si non quelqu'un doit le faire. Dans l'après-Drepper ère de la glibc est beaucoup mieux en fait la correction des bugs plutôt que de les fermer comme WONTFIX.Allait ajouter un commentaire, mais il a été un peu longue haleine ...
Je pense qu'il est clair à partir des réponses et les commentaires que
htonl()
doit être utilisé sur ces constantes (quoique que l'appelant surINADDR_ANY
etINADDR_NONE
équivaut à un non-ops). Le problème que je vois d'où la confusion se pose est qu'il n'est pas demandé explicitement dans les documents - quelqu'un s'il vous plaît corrigez-moi si j'ai tout simplement manqué, mais je n'ai pas vu dans les pages de manuel, ni dans l'en-tête où il est dit explicitement que le définit pourINADDR_*
sont hôte dans l'ordre. Encore une fois, pas une grosse affaire pourINADDR_ANY
,INADDR_NONE
, etINADDR_BROADCAST
, mais il est importante pourINADDR_LOOPBACK
.Maintenant, j'ai fait un peu de bas niveau socket en C, mais l'adresse de bouclage rarement, si jamais, est utilisé dans mon code. Bien que ce sujet soit plus d'un an, ce problème très simplement sauté à la mords-moi dans le derrière d'aujourd'hui, et c'est parce que je suis allé sur l'hypothèse erronée que les adresses définies dans l'en-tête sont dans le réseau de commande. Je ne sais pas pourquoi j'ai eu cette idée - sans doute parce que le
in_addr
structure doit avoir l'adresse de réseau de commande,inet_aton
etinet_addr
retour de leurs valeurs dans le réseau de l'ordre, et donc mon hypothèse logique était que ces constantes serait utilisable comme-est. Jetant un rapide 5-liner pour tester cette théorie, qui m'a montré le contraire. Si les pouvoirs-que-être arriver à voir cela, je voudrais faire la suggestion à appeler explicitement que les valeurs sont, en fait, l'hôte de l'ordre, pas de réseau de commande, et quehtonl()
doit être appliqué. Par souci de cohérence, je vous suggère aussi, comme d'autres l'ont déjà fait ici, quehtonl()
être utilisé pour toutes lesINADDR_*
valeurs, même si elle ne fait rien à la valeur.Stevens utilise
htonl(INADDR_ANY)
constamment dans le livre UNIX Réseau de Programmation (mon exemplaire est à partir de 1990).La version actuelle est la version de FreeBSD définit 12
INADDR_
constantes dansnetinet/in.h
; 9 des 12 exigerhtonl()
pour une bonne fonctionnalité. (Les 9 sontINADDR_LOOPBACK
et 8 autres de groupe de multidiffusion tels que les adressesINADDR_ALLHOSTS_GROUP
etINADDR_ALLMDNS_GROUP
.)Dans la pratique, il ne fait aucune différence si vous utilisez
INADDR_ANY
ouhtonl(INADDR_ANY)
, autres que le possible des performances dehtonl()
. Et de même que possible des performances peut ne pas exister, avec mon 64 bitsgcc 4.2.1
, tournant sur n'importe quel niveau de l'optimisation à tout semble activer au moment de la compilationhtonl()
conversion de constantes.En théorie, il serait possible de certains opérateur de redéfinir
INADDR_ANY
à une valeur oùhtonl()
réellement fait quelque chose, mais un tel changement permettrait de briser des dizaines de milliers de pièces existantes de code là-bas et ne survivrait pas dans le "monde réel"... Trop de code qui dépend explicitement ou implicitement surINADDR_ANY
être défini comme une sorte de valeur zéro entier. Stevens n'ont probablement pas l'intention d'inciter quiconque à assumer queINADDR_ANY
est toujours à zéro quand il a écrit:Résumons un peu, car aucune des réponses précédentes semble être à jour et je ne peut pas être la dernière personne qui va le voir, cette question de la page. Il y a eu opinions à la fois pour et contre l'utilisation de htonl autour de INADDR_ANY constante ou de les éviter complètement.
De nos jours (et c'est aujourd'hui, pour un certain temps maintenant) système de bibliothèques sont pour la plupart compatibles IPv6, donc nous utilisons IPv4 comme en IPv6. La situation avec l'IPv6 est beaucoup plus facile que les structures de données et les constantes ne souffrent pas de l'ordre des octets. On pourrait utiliser "in6addr_any' ainsi que 'in6addr_loopback" (les deux struct in6_addr type) et deux d'entre eux sont des objets constants dans l'ordre des octets de réseau.
Voir pourquoi l'IPv6 ne souffre pas du même problème (si les adresses IPv4 ont été définies comme les quatre tableaux d'octets qu'ils ne souffrent pas non plus):
Pour IPv4, il serait bien également d'avoir "inaddr_any" et "inaddr_loopback' comme 'struct in_addr constantes (de sorte qu'ils peuvent aussi être comparés avec memcmp ou copiés avec memcpy). En effet, il pourrait être une bonne idée de créer dans votre programme, car elles ne sont pas fournies par la glibc et d'autres bibliothèques:
Avec la glibc, cela ne fonctionne que pour moi, à l'intérieur d'une fonction (et je ne peux pas le faire
static
), commehtonl
n'est pas une macro, mais une fonction ordinaire.Le problème est que la glibc (en contraste avec ce qui a été affirmé dans les autres réponses) ne fournit pas de htonl comme une macro, mais plutôt comme une fonction. Par conséquent, vous devez:
Ce serait une belle addition pour les en-têtes et alors vous pouvez travailler avec IPv4 constantes aussi facilement que vous pouvez avec l'IPv6.
Mais de là à mettre en œuvre que j'ai eu à utiliser des constantes pour initialiser que. Quand je connaître les octets exactement, je n'ai pas besoin tout constantes. Tout comme certaines personnes prétendent que
htonl()
est redondante pour une constante qui prend la valeur zéro, personne d'autre ne pouvait prétendre que la constante elle-même est redondante. Et il serait droite.Dans le code, je préfère être explicite qu'implicite. Par conséquent, si ces constantes (comme INADDR_ANY, INADDR_ALL, INADDR_LOOPBACK) sont constamment dans l'ordre des octets de l'hôte, puis c'est correct si vous les traiter comme ça. Voir, par exemple, lorsqu'il n'est pas à l'aide de la constante):
Bien sûr, vous pourriez dire que vous n'avez pas besoin d'appeler
htonl
pour INADDR_ANY et, par conséquent, vous pouvez:Mais alors quand en ignorant l'ordre des octets de la constante de parce que c'est nul de toute façon, alors je ne vois pas bien la logique à l'aide de la constante à tous. Et la même chose s'applique à INADDR_ALL, comme il est facile de type 0xffffffff ainsi;
Une autre façon de contourner cela est d'éviter la fixation de ces valeurs directement tout:
Ça ajoute un peu inutile le traitement, mais il n'a pas d'ordre des octets de problèmes et il est pratiquement le même pour les protocoles IPv4 et IPv6 (il suffit de changer l'adresse de la chaîne).
Mais la question est de savoir pourquoi tu fais ça à tous les. Si vous voulez
connect()
de l'IPv4 localhost (mais parfois à l'IPv6 localhost, ou de n'importe quel nom d'hôte), getaddrinfo() (mentionné dans l'une des réponses) est beaucoup mieux pour que, comme:C'est une fonction utilisée pour la traduction de n'importe quelle machine/service/famille/socktype/protocole
pour une liste de correspondance
struct addrinfo
dossiers.Chaque
struct addrinfo
comprend un polymorphe pointeur versstruct sockaddr
que vous pouvez utiliser directement avecconnect()
. Vous n'avez donc pas besoin de se soucier de la construction destruct sockaddr_in
, typecasting (via un pointeur) àstruct sockaddr
, etc.struct addrinfo *ia, des notes = { .ai_family = AF_INET };
getaddrinfo(0, "1234", &astuces &ia);
enregistrement qui comprennent des pointeurs polymorphes
struct sockaddr
structures dont vous avez besoin pour laconnect()
appel.Donc, la conclusion est:
1) L'API standard ne parvient pas à fournir directement utilisable
struct in_addr
constantes (au contraire, il fournit plutôt inutile entier non signé constantes de l'hôte de la commande).Lorsque vous êtes sûr que votre requête est suffisamment sélectif qu'il ne retourne un résultat, vous pourriez faire (en omettant la gestion des erreurs pour des raisons de concision) suivantes:
Si vous avez peur
getaddrinfo()
pourrait être beaucoup plus lent que d'utiliser les constantes, le système de la bibliothèque est le meilleur endroit pour résoudre ce problème. Une bonne mise en œuvre serait juste retour de la demande adresse de bouclage lorsqueservice
est nulle ethints.ai_family
est réglé.Je n'ai pas l'habitude de répondre quand il y a déjà un "décent" réponse. Dans ce cas, je vais faire une exception parce que l'information que j'ai ajoutée à la réponse à ces questions est d'être mal interprété.
INADDR_ANY
est défini comme un zéro les bits d'adresse IPv4,0.0.0.0
ou0x00000000
. L'appel dehtonl()
sur cette valeur entraîne la même valeur zéro. Par conséquent, l'appelhtonl()
sur cette valeur de la constante n'est pas techniquement nécessaire.INADDR_ALL
est définie comme une de tous les bits de l'adresse IPv4,255.255.255.255
ou0xFFFFFFFF
. L'appel dehtonl()
avecINADDR_ALL
sera de retourINADDR_ALL
. Encore une fois, l'appel dehtonl()
n'est pas techniquement nécessaire.Une autre constante définie dans les fichiers d'en-tête est
INADDR_LOOPBACK
, définie comme127.0.0.1
, ou0x7F000001
. Cette adresse est donnée dans le réseau d'ordre d'octet, et ne peuvent être transmis à l'interface sockets sanshtonl()
. Vous devez utiliserhtonl()
avec cette constante.Certains suggèrent que la cohérence et la lisibilité du code à la demande que les programmeurs utilisent
htonl()
pour toute constante nomméeINADDR_*
-- car il est nécessaire pour certains d'entre eux. Ces affiches sont mauvais.Un exemple donné dans ce fil de discussion est:
Citant "Jean Zwinck":
"Si j'étais la révision de ce code, je le ferais immédiatement la question de savoir pourquoi l'une des constantes a htonl appliquée et l'autre pas. Et je le signaler comme un bug, si oui ou non il m'est arrivé d'avoir des "connaissances" que INADDR_ANY est toujours 0 si la conversion c'est un no-op. Et je pense (et espère) de nombreux autres responsables feraient la même chose."
Si je recevaient ce un rapport de bug, je voudrais immédiatement jeter. Ce processus me sauver beaucoup de temps, de la mise en service de rapports de bogues à partir de gens qui n'ont pas la "base de connaissances minimales" que
INADDR_ANY
est toujours 0. (Ce qui suggère que le fait de connaître les valeurs deINADDR_ANY
et coll. en quelque sorte, viole l'encapsulation ou tout ce qui est un autre non-starter-même les nombres sont utilisés dans lenetcat
de sortie et à l'intérieur du noyau. Les programmeurs ont besoin de connaître la forme de valeurs numériques. Les gens qui ne savent pas ne sont pas dépourvues de à l'intérieur de connaissances, ils manquent de base connaissance de la région.)Vraiment, si vous avez un programmeur maintien de sockets code, et que le programmeur n'a pas à connaître les motifs de bits de INADDR_ANY et INADDR_ALL, vous êtes déjà en difficulté. Habillage de 0 dans une macro qui renvoie 0, c'est le genre de mentalité qui est l'esclave des sens de la cohérence et de ne pas respecter les connaissances du domaine.
Maintien de sockets code, c'est plus que la compréhension de C. Si vous ne comprenez pas la différence entre
INADDR_LOOPBACK
etINADDR_ANY
à un niveau compatible avecnetstat
de sortie, alors vous êtes dangereux dans ce code et ne devrait pas être le changer.De la paille, l'homme des arguments proposés par Zwinck concernant l'inutile l'utilisation de
htonl()
:C'est une paille argument parce que nous avons une représentation qui expérimentés socket programmeurs connaissent la valeur de la
INADDR_ANY
par cœur. C'est comme d'écrire que seul un expérimentés programmeur C connaît la valeur deNULL
par cœur. L'écriture de "par cœur" donne l'impression que le nombre est légèrement difficile à mémoriser, peut-être un peu les chiffres, tels que127.0.0.1
. Mais non, nous sommes hyperbolically discuter de la difficile de mémoriser les habitudes nommée "zéro tous les bits" et "toutes les un bits."Considérant que ces valeurs numériques apparaissent dans la sortie de, par exemple,
netstat
et d'autres utilitaires de système, et considérant également que certaines de ces valeurs apparaissent dans les en-têtes IP, il n'y a pas une telle chose comme un compétent sockets programmeur qui ne connaissent pas ces valeurs, que ce soit par le coeur ou par le cerveau. En fait, la tentative de sockets de programmation sans la connaissance de ces bases peut être dangereux pour la disponibilité du réseau.Cet argument est destiné à être absurde et dédaigneux, il n'est pas besoin de beaucoup de le réfuter.
Il est difficile de savoir où cet argument vient. Il pourrait être une tentative de fourniture stupide-semblant arguments de l'opposition. En tout cas, pas à l'aide de la
htonl()
macro ne fait pas de différence de performances lorsque vous fournissez une constante et l'utilisation typique d'un compilateur C -- les expressions constantes sont réduits à une constante dans les deux cas.Une raison de ne pas utiliser
htonl()
avec INADDR_ANY, c'est que les plus expérimentés sockets programmeur sait qu'il n'est pas nécessaire. Quoi de plus: les programmeurs qui ne savent pas besoin d'apprendre. Il n'y a aucun "coût" avec l'utilisation dehtonl()
, le problème est le coût de l'établissement d'une norme de codage qui favorise l'ignorance d'une telle critique des valeurs importantes.Par définition, l'encapsulation favorise l'ignorance. Que très ignorance, c'est l'habitude de bénéficier de l'aide d'un encapsulé interface -- la connaissance est coûteux et limité et, par conséquent, l'encapsulation est généralement bonne. La question devient: quels efforts de programmation sont les mieux améliorée via l'encapsulation? Sont là des tâches de programmation qui sont disserved par encapsulation?
Il n'est pas techniquement incorrect d'utiliser
htonl()
, parce qu'il n'a pas d'effet sur cette valeur. Toutefois, les arguments que vous devrait utilisation, il peut être trompeuse.Il y a ceux qui diront qu'une meilleure situation serait celui dans lequel le développeur n'a pas besoin de savoir que
INADDR_ANY
est tous les zéros et ainsi de suite. Cette terre de l'ignorance est le pire, pas mieux. Considérer que ces "la magie des valeurs" sont utilisés tout au long des différentes interfaces avec le protocole TCP/IP. Par exemple, lors de la configuration d'Apache, si vous souhaitez écouter que pour IPv4 (et pas IPv6), vous devez spécifier:J'ai couru dans programmeurs qui, à tort, fourni l'adresse IP locale au lieu de
INADDR_ANY
(0.0.0.0) ci-dessus. Ces programmeurs ne sais pas ce queINADDR_ANY
est, et ils ont probablement l'envelopper danshtonl()
alors qu'ils sont à elle. C'est la terre de l'abstraction-la pensée et l'encapsulation.Les idées de "l'encapsulation" et "abstraction" ont été largement acceptés et trop largement appliquées, mais elles ne s'appliquent pas toujours. Dans le domaine de l'adressage IPv4, il n'est pas approprié pour traiter ces valeurs de constantes comme "abstrait" -- ils sont convertis directement en morceaux sur le fil.
Mon point est ceci: il n'y a pas de "bonne" utilisation de
INADDR_ANY
avechtonl()
-- les deux sont équivalents. Je ne recommande pas l'adoption d'une exigence que la valeur soit utilisée d'une manière particulière, parce que leINADDR_X
de la famille de constantes seulement quatre membres, et un seul d'entre eux,INADDR_LOOPBACK
a une valeur qui est différente en fonction de l'octet de commande. Il est préférable de savoir ce fait que d'établir un standard pour utiliser les valeurs qui transforme les "yeux" pour les modèles de bits des valeurs.Dans beaucoup d'autres Api, il est utile pour les programmeurs de procéder sans connaître la valeur numérique ou modèles de bits de constantes utilisées par l'Api. Dans le cas de l'API sockets, ces modèles de bits et les valeurs sont utilisées comme entrées et affichées de façon omniprésente. Il est préférable de connaître ces valeurs numériquement que de passer du temps à réfléchir sur l'utilisation de
htonl()
sur eux.Lors de la programmation en C, en particulier, la plupart des "utilisation" de l'API sockets consiste à passer de l'autre personne code source, et de l'adapter. C'est une autre raison, il est donc important de savoir ce que
INADDR_ANY
est avant de toucher à une ligne qui l'utilise.htonl
tandis que le membre distinct,INADDR_LOOPBACK
signifie quelque chose de très différent du reste. Permettant endormie "pas assez de café" changements est un non-but dans ce terrain. Penser au-delà de laINADDR_X
de la famille, vous ne pouvez pas faire des hypothèses sur une autre famille de constantes définies, ils pourraient déjàhtonl()
.