Вопрос о INADDR_ANY - PullRequest
       43

Вопрос о INADDR_ANY

4 голосов
/ 01 августа 2011

Константа INADDR_ANY - это так называемый подстановочный адрес IPv4.Подстановочный IP-адрес полезен для приложений, которые связывают сокеты домена Интернета на многосетевых хостах.Если приложение на многосетевом хосте привязывает сокет только к одному из IP-адресов своего хоста, тогда этот сокет может принимать только дейтаграммы 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-адресу, то сокет может принимать только запросы UPD / TCP, отправленные на этот IP-адрес.

Как я показываю вкод выше, теперь сокет 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

1 Ответ

11 голосов
/ 01 августа 2011

Он не получает запросы на каждый IP-адрес в Интернете (a) , он получает запросы на каждый IP-адрес, который он обслуживает.Например, он может иметь несколько сетевых адаптеров, каждый с отдельным IP-адресом, или может иметь один сетевой адаптер, способный управлять несколькими IP-адресами (может даже иметь несколько сетевых карт, каждый из которых способен обрабатывать несколько IP-адресов.

Вот ключевой фрагмент кода:

... обычно мы хотим, чтобы приложение на хосте с несколькими компьютерами получало дейтаграммы или запросы на подключение, которые указывают любой из IP-адресов хоста адреса (мой курсив).

Другими словами, у вас может быть многодомная настройка, где ваши машины обслуживают 10.0.0.15 и 10.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) Он даже не видит подавляющее большинство запросов в сети.Подавляющее большинство даже не добирается до ближайшего маршрутизатора (или, возможно, даже вашего интернет-провайдера).Даже те, которые do доберутся до ближайшего маршрутизатора, ваша конкретная машина может не увидеть, предназначены ли они для другой машины в локальном сегменте (несмотря на беспорядочный режим).

...