Linux 关于 INADDR_ANY 的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6894092/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:23:33  来源:igfitidea点击:

Question about INADDR_ANY

linuxtcpubuntu-10.04

提问by q0987

The constant INADDR_ANY is the so-called IPv4 wildcard address. The wildcard IP address is useful for applications that bind Internet domain sockets on multihomed hosts. If an application on a multihomed host binds a socket to just one of its host's IP addresses, then that socket can receive only UDP datagrams or TCP connection requests sent to that IP address. However, we normally want an application on a multihomed host to be able to receive datagrams or connection requests that specify any of the host's IP addresses, and binding the socket to the wildcard IP address makes this possible.

常量 INADDR_ANY 是所谓的 IPv4 通配符地址。通配符 IP 地址对于在多宿主主机上绑定 Internet 域套接字的应用程序很有用。如果多宿主主机上的应用程序仅将套接字绑定到其主机的 IP 地址之一,则该套接字只能接收发送到该 IP 地址的 UDP 数据报或 TCP 连接请求。但是,我们通常希望多宿主主机上的应用程序能够接收指定任何主机 IP 地址的数据报或连接请求,并且将套接字绑定到通配符 IP 地址使这成为可能。

struct sockaddr_in server_address;
int server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&server_address, 0, sizeof(struct sockaddr_in));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY); // here is my quesion
server_address.sin_port = htons(9734);

bind(server_sockfd, (struct sockaddr*)&server_address, sizeof(server_address));

Question>

问题>

If we bind the socket to a specific IP address, then the socket can only receive UPD/TCP requests sent sent to that IP address.

如果我们将套接字绑定到特定的 IP 地址,则套接字只能接收发送到该 IP 地址的 UPD/TCP 请求。

As I show in the above code, now the socket server_sockfd is bound with INADDR_ANY. I just feel confused here b/c if the socket can receive any request on the internet, how it can still work well. There are tons of requests of UDP/TCP on internet, if the socket responses to everybody, , how can it still work?

正如我在上面的代码中所示,现在套接字 server_sockfd 与 INADDR_ANY 绑定。我只是在这里感到困惑 b/c 如果套接字可以在互联网上接收任何请求,它如何仍然可以正常工作。互联网上有大量的UDP/TCP请求,如果socket对每个人都有响应,它怎么还能工作?

// updated code for client side //

// 更新客户端代码 //

int
main(int argc, char *argv[])
{
    struct sockaddr_in6 svaddr;
    int sfd, j;
    size_t msgLen;
    ssize_t numBytes;
    char resp[BUF_SIZE];

    if (argc < 3 || strcmp(argv[1], "--help") == 0)
        usageErr("%s host-address msg...\n", argv[0]);

    /* Create a datagram socket; send to an address in the IPv6 somain */

    sfd = socket(AF_INET6, SOCK_DGRAM, 0);      /* Create client socket */
    if (sfd == -1)
        errExit("socket");

    memset(&svaddr, 0, sizeof(struct sockaddr_in6));
    svaddr.sin6_family = AF_INET6;
    svaddr.sin6_port = htons(PORT_NUM);
    if (inet_pton(AF_INET6, argv[1], &svaddr.sin6_addr) <= 0)
        fatal("inet_pton failed for address '%s'", argv[1]);

    /* Send messages to server; echo responses on stdout */

    for (j = 2; j < argc; j++) {
        msgLen = strlen(argv[j]);
        if (sendto(sfd, argv[j], msgLen, 0, (struct sockaddr *) &svaddr,
                    sizeof(struct sockaddr_in6)) != msgLen)
            fatal("sendto");

        numBytes = recvfrom(sfd, resp, BUF_SIZE, 0, NULL, NULL);
        if (numBytes == -1)
            errExit("recvfrom");

        printf("Response %d: %.*s\n", j - 1, (int) numBytes, resp);
    }

    exit(EXIT_SUCCESS);
}

// updated for server side code

// 更新服务器端代码

int
main(int argc, char *argv[])
{
    struct sockaddr_in6 svaddr, claddr;
    int sfd, j;
    ssize_t numBytes;
    socklen_t len;
    char buf[BUF_SIZE];
    char claddrStr[INET6_ADDRSTRLEN];

    /* Create a datagram socket bound to an address in the IPv6 somain */

    sfd = socket(AF_INET6, SOCK_DGRAM, 0);
    if (sfd == -1)
        errExit("socket");

    memset(&svaddr, 0, sizeof(struct sockaddr_in6));
    svaddr.sin6_family = AF_INET6;
    svaddr.sin6_addr = in6addr_any;                     /* Wildcard address */
    svaddr.sin6_port = htons(PORT_NUM);

    if (bind(sfd, (struct sockaddr *) &svaddr,
                sizeof(struct sockaddr_in6)) == -1)
        errExit("bind");

    /* Receive messages, convert to uppercase, and return to client */

    for (;;) {
        len = sizeof(struct sockaddr_in6);
        numBytes = recvfrom(sfd, buf, BUF_SIZE, 0,
                            (struct sockaddr *) &claddr, &len);
        if (numBytes == -1)
            errExit("recvfrom");

        /* Display address of client that sent the message */

        if (inet_ntop(AF_INET6, &claddr.sin6_addr, claddrStr,
                    INET6_ADDRSTRLEN) == NULL)
            printf("Couldn't convert client address to string\n");
        else
            printf("Server received %ld bytes from (%s, %u)\n",
                    (long) numBytes, claddrStr, ntohs(claddr.sin6_port));

        for (j = 0; j < numBytes; j++)
            buf[j] = toupper((unsigned char) buf[j]);

        if (sendto(sfd, buf, numBytes, 0, (struct sockaddr *) &claddr, len) !=
                numBytes)
            fatal("sendto");
    }
}

// updated for how to run this server/client programs.

// 更新了如何运行此服务器/客户端程序。

$ ./server_program &
[1] 31047
$ ./client_program ::1 ciao // Send to server on local host
Server received 4 bytes from (::1, 32770)
Response 1: CIAO

采纳答案by paxdiablo

It doesn't get requests for every IP address on the internet(a), it gets requests for every IP address that it services. For example, it may have multiple NICs, each with a separate IP address or it may have a single NIC capable of managing multiple IP addresses (it may even have multiple NICs, each capable of handling multiple IP addresses.

它不会获取对 Internet (a) 上每个 IP 地址的请求,而是获取对其服务的每个 IP 地址的请求。例如,它可能有多个网卡,每个网卡都有一个单独的 IP 地址,或者它可能有一个能够管理多个 IP 地址的网卡(它甚至可能有多个网卡,每个网卡都能够处理多个 IP 地址。

The key snippet to look at is:

要查看的关键片段是:

... we normally want an application on a multi-homed host to be able to receive datagrams or connection requests that specify any of the host's IP addresses(my italics).

...我们通常希望多宿主主机上的应用程序能够接收指定任何主机 IP 地址的数据报或连接请求(我的斜体)。

In other words, you may have a multi-homed set-up where your machine services 10.0.0.15and 10.0.0.16. Using INADDR_ANYwill allow you to pick up traffic for both those addresses, withoutpicking up requests for 10.0.0.17which may be the machine on the other end of the bench (or other side of the planet).

换句话说,您可能有一个多宿主设置,您的机器在其中提供服务10.0.0.1510.0.0.16. 使用INADDR_ANY将允许您获取这两个地址的流量,而无需获取10.0.0.17可能是工作台另一端(或地球另一端)的机器的请求。

The following table, with the top row being request destinations and the left column being the address you're listening on, shows whether you'll be given a request (Y) or not (N):

下表,顶行是请求目的地,左列是您正在侦听的地址,显示您是否会收到请求 ( Y) 或不 ( N):

Request to>  10.0.0.15  10.0.0.16  10.0.0.17
Bind to:    *-------------------------------
10.0.0.15   |    Y          N          N
10.0.0.16   |    N          Y          N
INADDR_ANY  |    Y          Y          N


(a)It doesn't even seethe vast majority of requests on the net. The vast majority don't even make it to your nearest router (or probably even your ISP). Even those that domake it to your nearest router, your particular machine might not see if they're destined for another machine on the local segment (promiscuous mode notwithstanding).

(a)它甚至看不到网络上的绝大多数请求。绝大多数甚至没有到达您最近的路由器(甚至可能是您的 ISP)。即使是那些确实连接到离您最近的路由器的路由器,您的特定机器也可能看不到它们是否要去本地网段上的另一台机器(尽管存在混杂模式)。