C语言 sin_addr.s_addr = INADDR_ANY; 需要 htonl 吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6081892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does sin_addr.s_addr = INADDR_ANY; need htonl at all?
提问by compile-fan
I came across two threads:
我遇到了两个线程:
Socket with recv-timeout: What is wrong with this code?
带有 recv-timeout 的套接字:这段代码有什么问题?
Reading / Writing to a socket using a FILE stream in c
one uses htonland the other doesn't.
一个使用htonl,另一个没有。
Which is right?
哪个是对的?
回答by John Zwinck
Since other constants like INADDR_LOOPBACKare in host byte order, I submit that all the constants in this family should have htonlapplied to them, including INADDR_ANY.
由于其他常量如INADDR_LOOPBACK主机字节顺序,我认为该系列中的所有常量都应该htonl应用于它们,包括INADDR_ANY.
(Note: I wrote this answer while @Mat was editing; his answer now also says it's better to be consistent and always use htonl.)
(注意:我在@Mat 编辑时写了这个答案;他的答案现在还说最好保持一致并始终使用htonl。)
Rationale
基本原理
It is a hazard to future maintainers of your code if you write it like this:
如果你这样写,对你的代码的未来维护者来说是一种危险:
if (some_condition)
sa.s_addr = htonl(INADDR_LOOPBACK);
else
sa.s_addr = INADDR_ANY;
If I were reviewing this code, I would immediately question why one of the constants has htonlapplied and the other does not. And I would report it as a bug, whether or not I happened to have the "inside knowledge" that INADDR_ANYis always 0 so converting it is a no-op.
如果我正在查看此代码,我会立即质疑为什么其中一个常量已htonl应用而另一个未应用。而且我会将其报告为错误,无论我是否碰巧拥有INADDR_ANY始终为 0的“内部知识”,因此转换它是无操作的。
The code you write is not only about having the correct runtime behavior, it should also be obvious where possible and easy to believe it is correct. For this reason you should not strip out the htonlaround INADDR_ANY. The three reasons for not using htonlthat I can see are:
您编写的代码不仅是关于拥有正确的运行时行为,还应该在可能的情况下显而易见并且易于相信它是正确的。出于这个原因,你不应该去掉htonl周围的INADDR_ANY. htonl我可以看到不使用的三个原因是:
- It may offend experienced socket programmers to use
htonlbecause they will know it does nothing (since they know the value of the constant by heart). - It requires less typing to omit it.
- A bogus "performance" optimization (clearly it won't matter).
- 使用它可能会冒犯有经验的套接字程序员,
htonl因为他们会知道它什么也不做(因为他们知道常量的值)。 - 它需要较少的输入来省略它。
- 虚假的“性能”优化(显然无关紧要)。
回答by Mat
INADDR_ANYis the "any address" in IPV4. That address is 0.0.0.0in dotted notation, so 0x000000in hex on any endianness. Passing it through htonlhas no effect.
INADDR_ANY是 IPV4 中的“任意地址”。该地址采用0.0.0.0点号表示法,因此0x000000采用任何字节序的十六进制。通过它htonl没有任何影响。
Now if you want to wonder about other macro constants, look at INADDR_LOOPBACKif it's defined on your platform. Chances are it will be a macro like this:
现在,如果您想了解其他宏常量,请查看INADDR_LOOPBACK它是否在您的平台上定义。有可能是这样的宏:
#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
(from linux/in.h, equivalent definition in winsock.h).
(来自linux/in.h,中的等效定义winsock.h)。
So for INADDR_LOOPBACK, an htonlis necessary.
所以对于INADDR_LOOPBACK, anhtonl是必要的。
For consistency, it could thus be better to use htonlin all cases.
为了一致性,因此最好htonl在所有情况下使用。
回答by R.. GitHub STOP HELPING ICE
Neither is right, in the sense that both INADDR_ANYand htonlare deprecated, and lead to complex, ugly code that only works with IPv4. Switch to using getaddrinfofor all of your socket address creation needs:
两者都不对,从某种意义上说,INADDR_ANY和htonl都已弃用,并导致仅适用于 IPv4 的复杂、丑陋的代码。切换到getaddrinfo用于所有套接字地址创建需求:
struct addrinfo *ai, hints = { .ai_flags = AI_PASSIVE|AI_ADDRCONFIG };
getaddrinfo(0, "1234", &hints, &ai);
Replace "1234"with your port number or service name.
替换"1234"为您的端口号或服务名称。
回答by Will
Was going to add this as a comment, but it got a little long-winded ...
本来想把它作为评论添加的,但它有点啰嗦……
I think it's clear from the answers and the commentary here that htonl()needs to be used on these constants (albeit that calling it on INADDR_ANYand INADDR_NONEare tantamount to no-ops). The problem that I see as to where the confusion arises is that it is not explicitly called out in documentation - someone please correct me if I simply missed it, but I have not seen in the man pages, nor in the include header where it explicitly states that the defines for INADDR_*are in host order. Again, not a big deal for INADDR_ANY, INADDR_NONE, and INADDR_BROADCAST, but it issignificant for INADDR_LOOPBACK.
我认为从这里的答案和评论中可以清楚地看出,htonl()需要对这些常量使用(尽管调用它INADDR_ANY并且INADDR_NONE相当于无操作)。我认为出现混淆的问题是文档中没有明确指出它 - 如果我只是错过了它,请有人纠正我,但我没有在手册页中看到,也没有在包含标题中明确地看到它声明定义为INADDR_*主机顺序。同样,没有什么大不了的INADDR_ANY,INADDR_NONE以及INADDR_BROADCAST,但它是为显著INADDR_LOOPBACK。
Now, I've done quite a bit of low-level socket work in C, but the loopback address rarely, if ever, gets used in my code. Although this topic is over a year old, this very problem just jumped up to bite me in the behind today, and it was because I went on the mistaken assumption that the addresses defined in the include header are in network order. Not sure why I had that idea - probably because the in_addrstructure needs to have the address in network order, inet_atonand inet_addrreturn their values in network order, and so my logical assumption was that these constants would be usable as-is. Throwing together a quick 5-liner to test that theory showed me otherwise. If any of the powers-that-be happen to see this, I would make the suggestion to explicitly call out that the values are, in fact, in host order, not network order, and that htonl()should be applied to them. For consistency's sake, I would also suggest, as others have done so already here, that htonl()be used for all of the INADDR_*values, even if it does nothing to the value.
现在,我已经在 C 中完成了相当多的低级套接字工作,但是环回地址很少(如果有的话)在我的代码中使用。虽然这个话题已经有一年多了,但今天这个问题才突然跳起来咬我,这是因为我错误地认为include头中定义的地址是按网络顺序排列的。不知道为什么我有这个想法 - 可能是因为in_addr结构需要按网络顺序排列地址,inet_aton并且inet_addr按网络顺序返回它们的值,所以我的逻辑假设是这些常量可以按原样使用。将一个快速的 5-liner 组合在一起来测试这个理论,我发现并非如此。如果任何权力碰巧看到这一点,我会建议明确指出这些值实际上是主机顺序,而不是网络顺序,并且htonl()应该应用于它们。为了保持一致性,我还建议,正如其他人已经在这里所做的那样,将htonl()其用于所有INADDR_*值,即使它对值没有任何影响。
回答by Pavel ?imerda
Let's summarize it a little bit, as none of the previous answers seems to be up to date and I may not be the last person who will see this question page. There have been opinionsboth for and against usage of htonl around INADDR_ANY constant or avoiding it entirely.
让我们稍微总结一下,因为以前的答案似乎都不是最新的,而且我可能不是最后一个看到此问题页面的人。已经有意见支持和反对周围INADDR_ANY不断htonl的使用或避免它完全两者。
Nowadays (and it's been nowadays for quite some time now) system libraries are mostly IPv6 ready, so we use IPv4 as well as IPv6. The situation with IPv6 is much easier as the data structures and constants don't suffer from byte order. One would use 'in6addr_any' as well as 'in6addr_loopback' (both struct in6_addr type) and both of them are constant objects in the network byte order.
现在(现在已经有一段时间了)系统库大多支持 IPv6,所以我们使用 IPv4 和 IPv6。IPv6 的情况要容易得多,因为数据结构和常量不受字节顺序的影响。一种是使用 'in6addr_any' 和 'in6addr_loopback'(都是 struct in6_addr 类型),它们都是网络字节顺序中的常量对象。
See why IPv6 doesn't suffer from the same problem (if IPv4 addresses were defined as four byte arrays they wouldn't suffer either):
看看为什么 IPv6 不会遇到同样的问题(如果 IPv4 地址被定义为四字节数组,它们也不会遇到):
struct in_addr {
uint32_t s_addr; /* address in network byte order */
};
struct in6_addr {
unsigned char s6_addr[16]; /* IPv6 address */
};
For IPv4, it would be nice to also have 'inaddr_any' and 'inaddr_loopback' as 'struct in_addr' constants (so that they can also be compared with memcmp or copied with memcpy). Indeed it might be a good idea to create them in your program as they aren't provided by glibc and other libraries:
对于 IPv4,最好将 'inaddr_any' 和 'inaddr_loopback' 作为 'struct in_addr' 常量(这样它们也可以与 memcmp 进行比较或与 memcpy 一起复制)。实际上,在您的程序中创建它们可能是一个好主意,因为它们不是由 glibc 和其他库提供的:
const struct in_addr inaddr_loopback = { htonl(INADDR_LOOPBACK) };
With glibc, this only works for me inside a function (and I can't make it static), as htonlis not a macro but an ordinary function.
使用 glibc,这仅对我在函数内部有效(我无法做到static),因为htonl它不是宏而是普通函数。
The problem is that glibc (in contrast with what was claimed in other answers) doesn't provide htonl as a macro but rather as a function. Therefore you would have to:
问题是 glibc (与其他答案中声称的相反)没有将 htonl 作为宏提供,而是作为函数提供。因此,您必须:
static const struct in_addr inaddr_any = { 0 };
#if BYTE_ORDER == BIG_ENDIAN
static const struct in_addr inaddr_loopback = { 0x7f000001 };
#elif BYTE_ORDER == LITTLE_ENDIAN
static const struct in_addr inaddr_loopback = { 0x0100007f };
#else
#error Neither big endian nor little endian
#endif
That would be a really nice addition to the headers and then you could work with IPv4 constants as easily as you can with IPv6.
这将是对标头的一个非常好的补充,然后您可以像使用 IPv6 一样轻松地使用 IPv4 常量。
But then to implement that, I had to use some constants to initialize that. When I know the respective bytes exactly, I don't need anyconstants. Just as some people claim that htonl()is redundant for a constant that evaluates to zero, anyone else could claim that the constant itself is redundant as well. And he would be right.
但是为了实现它,我不得不使用一些常量来初始化它。当我确切地知道相应的字节时,我不需要任何常量。正如有些人声称htonl()对于计算为零的常数是多余的,其他任何人都可以声称常数本身也是多余的。他是对的。
In the code I prefer to be explicit than implicit. Therefore if those constants (like INADDR_ANY, INADDR_ALL, INADDR_LOOPBACK) are all consistently in host byte order, then it's only correct if you treat them like that. See for example (when not using the above constant):
在代码中,我更喜欢显式而不是隐式。因此,如果这些常量(如 INADDR_ANY、INADDR_ALL、INADDR_LOOPBACK)在主机字节顺序中都是一致的,那么只有这样对待它们才是正确的。参见示例(当不使用上述常量时):
struct in_addr address4 = { htonl(use_loopback ? INADDR_LOOPBACK : INADDR_ANY };
Of course you could say that you don't need to call htonlfor INADDR_ANY and therefore you could:
当然,您可以说您不需要调用htonlINADDR_ANY,因此您可以:
struct in_addr address4 = { use_loopback ? htonl(INADDR_LOOPBACK) : INADDR_ANY };
But then when ignoring the byte order of the constant becauseit's zero anyway, then I don't see much logic in using the constant at all. And the same applies to INADDR_ALL, as it's easy to type 0xffffffff as well;
但是当忽略常量的字节顺序时,因为它无论如何都是零,那么我根本看不到使用常量的太多逻辑。这同样适用于 INADDR_ALL,因为它也很容易输入 0xffffffff;
Another way to get around it is to avoid setting those values directly altogether:
另一种绕过它的方法是避免直接设置这些值:
struct in_addr address4;
inet_pton(AF_INET, "127.0.0.1", &address4);
This adds a little bit of useless processing but it has no byte order problems and it is virtually the same for IPv4 and IPv6 (you just change the address string).
这增加了一些无用的处理,但它没有字节顺序问题,而且 IPv4 和 IPv6 几乎相同(您只需更改地址字符串)。
But the question is why are you doing that at all. If you want to connect()to IPv4 localhost (but sometimes to IPv6 localhost, or just any hostname), getaddrinfo() (mentioned in one of the answers) is much better for that, as:
但问题是你为什么要这样做。如果您想使用connect()IPv4 本地主机(但有时使用 IPv6 本地主机,或只是任何主机名),getaddrinfo()(在其中一个答案中提到)对此要好得多,因为:
It is a function used for translating any hostname/service/family/socktype/protocol a to a list of matching
struct addrinforecords.Each
struct addrinfoincludes a polymorphic pointer tostruct sockaddrthat you can directly use withconnect(). Therefore you don't need to care about the construction ofstruct sockaddr_in, typecasting (via a pointer) tostruct sockaddr, etc.struct addrinfo *ai, hints = { .ai_family = AF_INET }; getaddrinfo(0, "1234", &hints, &ai);
record that in turn include pointers polymorphic
struct sockaddrstructures which you need for theconnect()call.
它是一个用于将任何主机名/服务/家庭/袜子类型/协议 a 转换为匹配
struct addrinfo记录列表的函数。每个都
struct addrinfo包含一个多态指针struct sockaddr,您可以直接将其与connect(). 因此,您无需关心 的构造struct sockaddr_in、类型转换(通过指针)到struct sockaddr等。struct addrinfo *ai, 提示 = { .ai_family = AF_INET }; getaddrinfo(0, "1234", &hints, &ai);
记录又包含调用
struct sockaddr所需的指针多态结构connect()。
So, the conclusion is:
所以,结论是:
1) The standard API fails to provide directly usable struct in_addrconstants (instead it provides rather useless unsigned integer constants in host order).
1) 标准 API 无法提供直接可用的struct in_addr常量(而是按主机顺序提供相当无用的无符号整数常量)。
struct addrinfo *ai, hints = { .ai_family = AF_INET, .ai_protocol = IPPROTO_TCP };
int error;
error = getaddrinfo(NULL, 80, &hints, &ai);
if (error)
...
for (item = result; item; item = item->ai_next) {
sock = socket(item->ai_family, item->ai_socktype, item->ai_protocol);
if (sock == -1)
continue;
if (connect(sock, item->ai_addr, item->ai_addrlen) != -1) {
fprintf(stderr, "Connected successfully.");
break;
}
close(sock);
}
When you are sure your query is selective enough that it only returns one result, you could do (omitting error handling for brevity) the following:
当您确定您的查询具有足够的选择性以至于它只返回一个结果时,您可以执行以下操作(为简洁起见省略错误处理):
struct *result, hints = { .ai_family = AF_INET, .ai_protocol = IPPROTO_TCP };
getaddrinfo(NULL, 80, &hints, &ai);
sock = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
connect(sock, result->ai_addr, result->ai_addrlen);
If you're afraid getaddrinfo()might be significantly slower than using the constants, the system library is the best place to fix that. A good implementation would just return the requested loopback address when serviceis null and hints.ai_familyis set.
如果您担心getaddrinfo()可能比使用常量慢得多,那么系统库是解决该问题的最佳场所。一个好的实现只会在service为空并hints.ai_family设置时返回请求的环回地址。
回答by John Brennen
Stevens uses htonl(INADDR_ANY)consistently in the book UNIX Network Programming(my copy is from 1990).
Stevenshtonl(INADDR_ANY)在UNIX Network Programming(我的副本是 1990 年的)一书中始终如一地使用。
The current release version of FreeBSD defines 12 INADDR_constants in netinet/in.h; 9 of the 12 require htonl()for proper functionality. (The 9 are INADDR_LOOPBACKand 8 other multicast group addresses such as INADDR_ALLHOSTS_GROUPand INADDR_ALLMDNS_GROUP.)
FreeBSD 的当前发行版定义了 12 个INADDR_常量netinet/in.h;12 个中的 9 个需要htonl()正确的功能。(这 9 个是INADDR_LOOPBACK和 8 个其他多播组地址,例如INADDR_ALLHOSTS_GROUP和INADDR_ALLMDNS_GROUP。)
In practice, it makes no difference whether you use INADDR_ANYor htonl(INADDR_ANY), other than the possible performance hit from htonl(). And even that possible performance hit may not exist -- with my 64-bit gcc 4.2.1, turning on any level of optimization at all seems to activate compile-time htonl()conversion of constants.
在实践中,使用INADDR_ANY或没有任何区别htonl(INADDR_ANY),除了可能会影响htonl(). 甚至可能不存在可能的性能gcc 4.2.1下降——对于我的 64 位,打开任何级别的优化似乎都激活htonl()了常量的编译时转换。
In theory it would be possible for some implementer to redefine INADDR_ANYto a value where htonl()actually does something, but such a change would break tens of thousands of existing pieces of code out there and wouldn't survive in the "real world"... Too much code exists which depends explicitly or implicitly on INADDR_ANYbeing defined as some sort of zero-valued integer. Stevens likely didn't intend for anyone to assume that INADDR_ANYis always zero when he wrote:
从理论上讲,某些实现者可以重新定义INADDR_ANY一个htonl()实际执行某些操作的值,但是这样的更改会破坏那里的数万条现有代码并且无法在“现实世界”中生存......存在许多代码显式或隐式地依赖于INADDR_ANY被定义为某种零值整数。史蒂文斯INADDR_ANY在写道:
cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); cli_addr.sin_port = htons(0);In assigning a local address for the client using
bind, we set the Internet address toINADDR_ANYand the 16-bit Internet port to zero.
cli_addr.sin_addr.s_addr = htonl(INADDR_ANY); cli_addr.sin_port = htons(0);在使用 为客户端分配本地地址时
bind,我们将 Internet 地址设置INADDR_ANY为 16 位 Internet 端口为零。
回答by Heath Hunnicutt
I don't usually like to answer when there is already a "decent" answer. In this case, I am going to make an exception because information I added to these answers is being misconstrued.
当已经有了“体面”的答案时,我通常不喜欢回答。在这种情况下,我将破例,因为我添加到这些答案中的信息被误解了。
INADDR_ANYis defined as an all-zero-bits IPv4 address, 0.0.0.0or 0x00000000. Calling htonl()on this value will result in the same value, zero. Therefore, calling htonl()on this constant value is not technically necessary.
INADDR_ANY定义为全零位 IPv4 地址,0.0.0.0或0x00000000. 调用htonl()此值将产生相同的值,即零。因此,调用htonl()这个常量值在技术上是没有必要的。
INADDR_ALLis defined as an all-one-bits IPv4 address, 255.255.255.255or 0xFFFFFFFF. Calling htonl()with INADDR_ALLwill return INADDR_ALL. Again, calling htonl()is not technically necessary.
INADDR_ALL定义为全 1 位 IPv4 地址,255.255.255.255或0xFFFFFFFF. 调用htonl()withINADDR_ALL将返回INADDR_ALL。同样,调用htonl()在技术上不是必需的。
Another constant defined in the header files is INADDR_LOOPBACK, defined as 127.0.0.1, or 0x7F000001. This address is given in network-byte order, and cannot be passed to the sockets interface without htonl(). You must use htonl()with this constant.
头文件中INADDR_LOOPBACK定义的另一个常量是, 定义为127.0.0.1, 或0x7F000001。该地址以网络字节顺序给出,没有htonl(). 您必须htonl()与此常量一起使用。
Some would suggest that consistency and code readability demand that programmers use htonl()for any constant named INADDR_*-- because it is required for some of them. These posters are wrong.
有些人会认为一致性和代码可读性要求程序员htonl()用于任何命名的常量INADDR_*——因为它是其中一些所必需的。这些海报是错误的。
An example given in this thread is:
此线程中给出的示例是:
if (some_condition)
sa.s_addr = htonl(INADDR_LOOPBACK);
else
sa.s_addr = INADDR_ANY;
Quoting from "John Zwinck":
引自“约翰·茨温克”:
"If I were reviewing this code, I would immediately question why one of the constants has htonl applied and the other does not. And I report it as a bug, whether or not I happened to have the "inside knowledge" that INADDR_ANY is always 0 so converting it is a no-op. And I think (and hope) many other maintainers would do the same."
“如果我正在查看此代码,我会立即质疑为什么其中一个常量应用了 htonl 而另一个没有应用。我将其报告为一个错误,无论我是否碰巧拥有 INADDR_ANY 始终为的“内部知识” 0 所以转换它是一个空操作。我认为(并希望)许多其他维护者也会这样做。”
If I were receiving such a bug report, I would immediately throw it away. This process would save me a lot of time, fielding bug reports from people who don't have the "basic minimum knowledge" that INADDR_ANYis always 0. (Suggesting that knowing the values of INADDR_ANYet al. somehow violates encapsulation or whatever is another non-starter -- the same numbers are used in the netcatoutput and inside the kernel. Programmers need to know the actual numerical values. People who don't know aren't lacking insideknowledge, they are lacking basicknowledge of the area.)
如果我收到这样的错误报告,我会立即将其丢弃。这个过程可以为我节省很多时间,从那些没有“基本最低知识”的人那里得到错误报告,这些知识INADDR_ANY总是为 0。(暗示知道INADDR_ANYet al.的值不知何故违反了封装或其他非 - starter --netcat输出和内核内部使用相同的数字。程序员需要知道实际的数值。不知道的人并不缺乏内部知识,他们缺乏该领域的基础知识。)
Really, if you have a programmer maintaining sockets code, and that programmer doesn't know the bit patterns of INADDR_ANY and INADDR_ALL, you are already in trouble. Wrapping 0 in a macro which returns 0 is the kind of mentality that is a slave to meaningless consistency and doesn't respect domain knowledge.
真的,如果你有一个程序员维护套接字代码,而那个程序员不知道 INADDR_ANY 和 INADDR_ALL 的位模式,那么你已经有麻烦了。将 0 包装在返回 0 的宏中是一种心态,这种心态是无意义一致性的奴隶,不尊重领域知识。
Maintaining sockets code is about more than understanding C. If you don't understand the difference between INADDR_LOOPBACKand INADDR_ANYat a level compatible with netstatoutput, then you are dangerous in that code and shouldn't be changing it.
维护套接字代码不仅仅是了解 C。如果您不了解输出之间的区别INADDR_LOOPBACK以及INADDR_ANY与netstat输出兼容的级别,那么您在该代码中很危险,不应该更改它。
Straw-man arguments proposed by Zwinck regarding the needless use of htonl():
Zwinck 提出的关于不必要使用的稻草人论点htonl():
- It may offend experienced socket programmers to use htonl because they will know it does nothing (since they know the value of the constant by heart).
- 使用 htonl 可能会冒犯有经验的套接字程序员,因为他们知道它什么也不做(因为他们知道常量的值)。
This is a straw argument because we have a portrayal that experiencedsocket programmers know the value of INADDR_ANYby heart. This is like writing that only an experiencedC programmer knows the value of NULLby heart. Writing "by heart" gives the impression that the number is slight difficult to memorize, perhaps a few digits, such as 127.0.0.1. But no, we are hyperbolically discussing the difficult of memorizing the patterns named "all zero bits" and "all one bits."
这是一个草率的论点,因为我们有一个写照,经验丰富的套接字程序员都知道它的价值INADDR_ANY。这就像编写只有经验丰富的C 程序员才知道的价值NULL。“用心”书写给人的印象是数字有点难以记忆,可能是几个数字,例如127.0.0.1。但是不,我们正在夸张地讨论记住名为“全零位”和“全一位”的模式的难度。
Considering that these numerical values appear in the output of, e.g., netstatand other system utilities, and also considering that some of these values appear in IP headers, there is no such thing as a competent sockets programmer who does not know these values, whether by heart or by brain. In fact, attempting sockets programming without knowing these basics can be dangerous to the network availability.
考虑到这些数值出现在例如netstat和其他系统实用程序的输出中,并且还考虑到这些值中的一些出现在 IP 标头中,那么不知道这些值的称职的套接字程序员是不存在的,无论是通过心脏或大脑。事实上,在不了解这些基础知识的情况下尝试套接字编程可能会对网络可用性造成危险。
- It requires less typing to omit it.
- 它需要较少的输入来省略它。
This argument is intended to be absurd and dismissive, so it doesn't need much refuting.
这个论点是荒谬和不屑一顾的,所以不需要太多反驳。
- A bogus "performance" optimization (clearly it won't matter).
- 虚假的“性能”优化(显然无关紧要)。
It's hard to know where this argument came from. It could be an attempt to supply stupid-seeming arguments to the opposition. In any case, not using the htonl()macro makes no difference to performance when you provide a constant and use a typical C compiler -- the constant expressions are reduced to a constant in either case.
很难知道这个论点从何而来。这可能是试图向反对派提供看似愚蠢的论点。在任何情况下,htonl()当您提供常量并使用典型的 C 编译器时,不使用宏对性能没有任何影响——在任何一种情况下,常量表达式都被简化为常量。
A reason not to use htonl()with INADDR_ANY is that most experienced sockets programmer knows that it is not needed. What's more: those programmers who do not know need to learn. There is no extra "cost" with use of htonl(), the trouble is the cost of establishing a coding standard which fosters ignorance of such critically important values.
不htonl()与 INADDR_ANY一起使用的一个原因是大多数有经验的套接字程序员都知道它是不需要的。更重要的是:那些不知道的程序员需要学习。使用 没有额外的“成本” htonl(),问题在于建立编码标准的成本,这会导致对这些至关重要的值的无知。
By definition, encapsulation fosters ignorance. That very ignorance is the usual benefit of using an encapsulated interface -- knowledge is expensive and finite, therefore encapsulation is usually good. The question becomes: which efforts of programming are best enhanced via encapsulation? Are there programming tasks which are disserved by encapsulation?
根据定义,封装助长了无知。这种无知是使用封装接口的通常好处——知识是昂贵且有限的,因此封装通常是好的。问题变成了:通过封装最好地增强了哪些编程工作?是否存在封装不考虑的编程任务?
It is not technically incorrect to use htonl(), because it has no effect on this value. However, arguments that you shoulduse it may be misleading.
使用 并不是技术上不正确的htonl(),因为它对这个值没有影响。但是,您应该使用它的论点可能会产生误导。
There are those who would argue that a better situation would be one in which the developer did not needto know that INADDR_ANYis all zeroes and so on. This land of ignorance is worse, not better. Consider that these "magic values" are used throughout various interfaces with TCP/IP. For example, when configuring Apache, if you would like to listen only to IPv4 (and not IPv6), you must specify:
有些人会争辩说,更好的情况是开发人员不需要知道INADDR_ANY全为零等等。这片无知的土地更糟,而不是更好。考虑到这些“魔法值”在与 TCP/IP 的各种接口中使用。例如,在配置 Apache 时,如果您只想侦听 IPv4(而不是 IPv6),则必须指定:
Listen 0.0.0.0:80
I have run into programmers who mistakenly supplied the local IP address instead of INADDR_ANY(0.0.0.0) above. These programmers don't know what INADDR_ANYis, and they probably wrap it in htonl()while they are at it. This is the land of abstaction-thinking and encapsulating.
我遇到过错误地提供本地 IP 地址而不是INADDR_ANY上面的(0.0.0.0) 的程序员。这些程序员不知道是什么INADDR_ANY,他们可能在做的htonl()时候把它包装起来。这是抽象思维和封装的土地。
The ideas of "encapsulation" and "abstraction" have been widely accepted and too-widely applied, but they do not always apply. In the domain of IPv4 addressing, it's not appropriate to treat these constant values as "abstract" -- they are converted directly into bits on the wire.
“封装”和“抽象”的思想已经被广泛接受和应用太广泛,但它们并不总是适用。在 IPv4 寻址领域中,将这些常量值视为“抽象”是不合适的——它们在线路上直接转换为位。
My point is this: there is no "correct" usage of INADDR_ANYwith htonl()-- both are equivalent. I would not recommend adopting a requirement that the value be used any particular way, because the INADDR_Xfamily of constants only have four members, and only one of them, INADDR_LOOPBACKhas a value which is different depending on byte ordering. It is better to just know this fact than to establish a standard for using the values which turns a "blind eye" to the bit patterns of the values.
我的观点是:INADDR_ANYwith没有“正确”的用法htonl()——两者是等价的。我不建议采用以任何特定方式使用值的要求,因为INADDR_X常量族只有四个成员,并且只有其中一个成员INADDR_LOOPBACK具有根据字节顺序而不同的值。只知道这个事实比建立一个使用这些值的标准要好得多,这使得对值的位模式“视而不见”。
In many other APIs, it is valuable for programmers to proceed without knowing the numeric value or bit patterns of constants used by the APIs. In the case of the sockets API, these bit patterns and values are used as input and displayed pervasively. It is better to know these values numerically than to spend time thinking about using htonl()on them.
在许多其他 API 中,程序员在不知道 API 使用的常量的数值或位模式的情况下继续进行是很有价值的。在套接字 API 的情况下,这些位模式和值用作输入并普遍显示。最好以数字方式了解这些值,而不是花时间考虑使用htonl()它们。
When programming in C, especially, most "use" of the sockets API involves grabbing some other person's source code, and adapting it. This is another reason it is so important to know what INADDR_ANYis before touching a line which uses it.
尤其是在用 C 编程时,套接字 API 的大多数“使用”涉及抓取其他人的源代码并对其进行调整。这是另一个原因,INADDR_ANY在接触使用它的线之前知道什么是非常重要的。

