【问题标题】:Question about INADDR_ANY关于 INADDR_ANY 的问题
【发布时间】:2011-10-17 04:04:37
【问题描述】:

常量 INADDR_ANY 就是所谓的 IPv4 通配符地址。这 通配符 IP 地址对于绑定 Internet 的应用程序很有用 多宿主主机上的域套接字。如果多宿主上的应用程序 host 将一个套接字绑定到它的主机的一个 IP 地址,然后 socket 只能接收 UDP 数据报或发送的 TCP 连接请求 到那个 IP 地址。但是,我们通常希望在 多宿主主机能够接收数据报或连接请求 指定任何主机的 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));

问题>

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

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

// 客户端更新代码 //

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);
}

//为服务器端代码更新

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");
    }
}

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

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

【问题讨论】:

    标签: linux tcp ubuntu-10.04


    【解决方案1】:

    它不会为互联网上的每个 IP 地址获取请求(a),它会为它所服务的每个 IP 地址获取请求。例如,它可能有多个 NIC,每个都有一个单独的 IP 地址,或者它可能有一个能够管理多个 IP 地址的 NIC(它甚至可能有多个 NIC,每个 NIC 都能够处理多个 IP 地址。

    sn-p要看的关键是:

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

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

    下表,第一行是请求目标,左列是您正在侦听的地址,显示了您是否会收到请求 (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) 它甚至没有看到网络上的绝大多数请求。绝大多数甚至没有到达您最近的路由器(甚至可能是您的 ISP)。即使那些确实到达最近的路由器,你的特定机器也可能看不到它们是否发往本地网段上的另一台机器(尽管是混杂模式)。

    【讨论】:

    • @q0987 除非请求某种诊断模式(即“数据包嗅探”),否则操作系统的网络堆栈不会将不打算用于该机器地址之一的 IP 流量传递给程序。通常在较低级别和/或交换网络中进行适当的数据包寻址将防止大部分错误地址流量甚至达到网络堆栈的 IP 级别。
    • 请查看更新的客户端代码。客户端代码未指定服务器 IP 地址,在您的情况下,它未指定 10.0.0.15 到 10.0.0.16 范围内的任何 ip。那么服务器怎么知道客户端向它发送了请求呢?
    • @q0987 套接字服务器无法从未指定要发送到的 IP 地址的客户端获取流量(尽管可以指定广播地址)。同样,服务器确实必须指定一个接收地址,但该地址可以是“这台计算机的任何地址”
    • @q0987,您的客户端代码确实指定了服务器地址,inet_pton 位于argv[1] 上。此调用采用类似10.0.0.15 的表示格式并将其转换为二进制网络地址。换句话说,它是在命令行上传递的。见kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html
    • @q0987:不完全是。 ::1 一个IP地址,你确实指定了它。它是 IPv4 127.0.0.1 的 IPv6 等价物。环回地址 (localhost) 可以方便地表示当前主机,但它与任何其他 IP 地址一样有效。几乎可以肯定,它是通过指定 INADDR_ANY 提供服务的 IP 地址之一。
    猜你喜欢
    • 2021-11-29
    • 2011-09-22
    • 2018-05-23
    • 2011-11-16
    • 2021-03-27
    • 2017-01-27
    • 2011-10-31
    • 2011-01-19
    • 2011-07-20
    相关资源
    最近更新 更多