Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C sin_addr.s_addr=INADDR_;需要htonl吗?_C_Sockets - Fatal编程技术网

C sin_addr.s_addr=INADDR_;需要htonl吗?

C sin_addr.s_addr=INADDR_;需要htonl吗?,c,sockets,C,Sockets,我遇到了两条线索: 一个使用htonl,另一个不使用 哪个是对的?INADDR\u ANY是IPV4中的“任意地址”。该地址是点符号形式的0.0.0.0,因此在任何端点上都是十六进制形式的0x000000。将其通过htonl无效 现在,如果您想了解其他宏常量,请查看INADDR\u LOOPBACK它是否在您的平台上定义。很可能是这样一个宏: #define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ if (some_conditi

我遇到了两条线索:

一个使用
htonl
,另一个不使用


哪个是对的?

INADDR\u ANY
是IPV4中的“任意地址”。该地址是点符号形式的
0.0.0.0
,因此在任何端点上都是十六进制形式的
0x000000
。将其通过
htonl
无效

现在,如果您想了解其他宏常量,请查看
INADDR\u LOOPBACK
它是否在您的平台上定义。很可能是这样一个宏:

#define INADDR_LOOPBACK     0x7f000001  /* 127.0.0.1   */
if (some_condition)
    sa.s_addr = htonl(INADDR_LOOPBACK);
else
    sa.s_addr = INADDR_ANY;
(来自
linux/in.h
,与
winsock.h
中的等效定义)

因此,对于
INADDR\u环回
,需要
htonl


为了保持一致性,因此最好在所有情况下都使用
htonl

由于其他常量(如
INADDR\u LOOPBACK
)是按主机字节顺序排列的,因此我认为此族中的所有常量都应该应用
htonl
,包括
INADDR\u ANY

(注意:我在@Mat编辑时写下了这个答案;他的答案现在还说最好保持一致,并始终使用
htonl

基本原理

如果您这样编写代码,将对未来的代码维护人员造成危害:

#define INADDR_LOOPBACK     0x7f000001  /* 127.0.0.1   */
if (some_condition)
    sa.s_addr = htonl(INADDR_LOOPBACK);
else
    sa.s_addr = INADDR_ANY;
如果我在查看这段代码,我会立即问为什么其中一个常量应用了
htonl
,而另一个没有。我会将它报告为一个bug,不管我是否碰巧有“内部知识”,即
INADDR\u ANY
始终为0,因此转换它是不可行的

您编写的代码不仅仅是关于拥有正确的运行时行为,它还应该尽可能明显,并且容易让人相信它是正确的。因此,您不应在
INADDR\u ANY
周围去掉
htonl
。我可以看到不使用
htonl
的三个原因:

  • 使用
    htonl
    可能会冒犯有经验的套接字程序员,因为他们知道它不起任何作用(因为他们熟记常量的值)
  • 省略它需要更少的输入
  • 虚假的“性能”优化(显然这无关紧要)

  • 我通常不喜欢在已经有了“体面”的答案时回答。在这种情况下,我将破例,因为我添加到这些答案中的信息被误解了


    INADDR\u ANY
    定义为全零位IPv4地址、
    0.0.0
    0x00000000
    。对此值调用
    htonl()
    ,将得到相同的值零。因此,从技术上讲,对该常量值调用
    htonl()

    INADDR\u ALL
    被定义为一个全一位IPv4地址,
    255.255.255
    0xffffff
    。使用
    INADDR\u ALL
    调用
    htonl()
    将返回
    INADDR\u ALL
    。同样,调用
    htonl()
    在技术上也不是必需的

    头文件中定义的另一个常量是
    INADDR\u LOOPBACK
    ,定义为
    127.0.0.1
    ,或
    0x7F000001
    。此地址以网络字节顺序给出,如果没有
    htonl()
    ,则无法将其传递到套接字接口。必须对该常量使用
    htonl()

    有些人认为,一致性和代码可读性要求程序员对任何名为
    INADDR.*
    的常量使用
    htonl()
    ——因为有些常量是必需的。这些海报是错的

    本线程中给出的示例如下:

    if (some_condition)
        sa.s_addr = htonl(INADDR_LOOPBACK);
    else
        sa.s_addr = INADDR_ANY;
    
    引用“John Zwinck”的话:

    “如果我在查看这段代码,我会立即质疑为什么其中一个常量应用了htonl,而另一个没有。我将其报告为一个bug,我是否碰巧有“内部知识”,即INADR_ANY始终为0,因此转换它是不可行的。我认为(并希望)许多其他维护人员也会这样做。”

    如果我收到这样一个bug报告,我会立即扔掉它。这个过程将节省我很多时间,处理那些不具备
    INADDR\u ANY
    始终为0的“基本最低知识”的人的bug报告。(这意味着知道
    INADDR\u ANY
    等的值。不知何故违反了封装或其他非启动程序——在
    netcat
    输出和内核中使用相同的数字。程序员需要知道实际的数值。不知道的人并不缺乏内部知识,他们缺乏该领域的基本知识。)

    实际上,如果您有一个程序员维护套接字代码,而该程序员不知道INADDR_ANY和INADDR_ALL的位模式,那么您已经有麻烦了。将0包装在返回0的宏中是一种心态,它是无意义一致性的奴隶,不尊重领域知识

    维护套接字代码不仅仅是理解C。如果您不理解
    INADDR\u环回
    INADDR\u ANY
    在与
    netstat
    输出兼容的级别上的区别,那么您在该代码中是危险的,不应该更改它

    Zwinck提出的关于不必要使用
    htonl()
    的草人论点:

  • 使用htonl可能会冒犯有经验的套接字程序员,因为他们知道它不起任何作用(因为他们熟记常量的值)
  • 这是一个草率的论点,因为我们有一个描述,有经验的套接字程序员知道
    INADDR\u ANY
    的价值。这就像写一篇只有经验丰富的C程序员才能记住
    NULL
    的值一样。“背诵”给人的印象是数字有点难记,可能是几个数字,比如
    127.0.0.1
    。但是不,我们夸张地讨论了记忆“全零位”模式的困难
    cli_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    cli_addr.sin_port        = htons(0);
    
    struct in_addr {
        uint32_t       s_addr;     /* address in network byte order */
    };
    
    struct in6_addr {
        unsigned char   s6_addr[16];   /* IPv6 address */
    };
    
    const struct in_addr inaddr_loopback = { htonl(INADDR_LOOPBACK) };
    
    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
    
    struct in_addr address4 = { htonl(use_loopback ? INADDR_LOOPBACK : INADDR_ANY };
    
    struct in_addr address4 = { use_loopback ? htonl(INADDR_LOOPBACK) : INADDR_ANY };
    
    struct in_addr address4;
    
    inet_pton(AF_INET, "127.0.0.1", &address4);
    
    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);
    }
    
    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);