关于INADDR_ANY的问题

q09*_*987 4 linux tcp ubuntu-10.04

常量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));
Run Code Online (Sandbox Code Playgroud)

问>

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

正如我在上面的代码中所示,现在套接字server_sockfd与INADDR_ANY绑定.我只是感到困惑,如果套接字可以在互联网上接收任何请求,它如何仍然可以正常工作b/c.在互联网上有大量的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);
}
Run Code Online (Sandbox Code Playgroud)

//为服务器端代码更新

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");
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

pax*_*blo 11

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

要看的关键片段是:

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

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

下表中,顶行是请求目标,左列是您正在侦听的地址,显示您是否会收到request(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
Run Code Online (Sandbox Code Playgroud)

(a)它甚至没有看到网上的绝大多数请求.绝大多数甚至没有到最近的路由器(或者甚至是你的ISP).即使那些确实能够到达最近的路由器,您的特定机器也可能看不到它们是否指定本地段上的另一台机器(尽管有混杂模式).

  • @ q0987,你的客户端代码_does_指定服务器地址,在`argv [1]`上使用`inet_pton`.此调用采用类似`10.0.0.15`的表示格式,并将其转换为二进制网络地址.换句话说,它是在命令行上传递的.见http://www.kernel.org/doc/man-pages/online/pages/man3/inet_pton.3.html (2认同)