Почему bind возвращает один и тот же эфемерный порт? - PullRequest
3 голосов
/ 21 февраля 2012

У меня есть проблема, когда я создаю два UDP-сокета, связываю их с адресом обратной связи с портом 0 (запрашиваю стек для назначения эфемерного порта). Насколько я понимаю, оба сокета должны быть на разных портах. В приведенном ниже примере кода сообщается, что оба сокета находятся на одном IP-адресе и порте.

#include <stdio.h>
#include <arpa/inet.h>

int main(int, char**)
{
    int fd1 = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (fd1 < 0)
    {
        perror("fd1 socket()");
        return -1;
    }
    int fd2 = ::socket(AF_INET, SOCK_DGRAM, 0);
    if (fd2 < 0)
    {
        perror("fd2 socket()");
        return -1;
    }

    // Set SO_REUSEADDR for both sockets
    int reuse = 1;
    if (::setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        perror("fd1 SO_REUSEADDR failed");
        return -1;
    }
    if (::setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
    {
        perror("fd2 SO_REUSEADDR failed");
        return -1;
    }

    sockaddr_storage storage;
    socklen_t addrlen = sizeof(storage);
    sockaddr_in& addr = reinterpret_cast<sockaddr_in&>(storage);
    addr.sin_family = AF_INET;
    addr.sin_port = 1234;
    addr.sin_port = 0;
    if (::inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr) <= 0)
    {
        perror("Failed to create address 127.0.0.1");
        return -1;
    }
    sockaddr* pAddr = reinterpret_cast<sockaddr*>(&storage);

    if (::bind(fd1, pAddr, addrlen) < 0)
    {
        perror("bind fd1 failed");
        return -1;
    }

    // Get the local address for fd1
    addrlen = sizeof(storage);
    if (::getsockname(fd1, pAddr, &addrlen))
    {
        perror("getsockname for fd1 failed");
        return -1;
    }
    char straddr[INET_ADDRSTRLEN];
    if (!inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr)))
    {
        perror("inet_ntop for fd1 failed");
        return -1;
    }
    printf("fd1=%d addr=%s:%d\n", fd1, straddr, addr.sin_port);

    if (::bind(fd2, pAddr, addrlen) < 0)
    {
        perror("bind fd2 failed");
        return -1;
    }

    // Get the local address for fd2
    addrlen = sizeof(storage);
    if (::getsockname(fd2, pAddr, &addrlen))
    {
        perror("getsockname for fd2 failed");
        return -1;
    }
    if (!inet_ntop(AF_INET, &addr.sin_addr, straddr, sizeof(straddr)))
    {
        perror("inet_ntop for fd2 failed");
        return -1;
    }
    printf("fd2=%d addr=%s:%d\n", fd2, straddr, addr.sin_port);

    return 0;
}

Этот код дает следующий вывод ...

fd1=4 addr=127.0.0.1:1933
fd2=5 addr=127.0.0.1:1933

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

1 Ответ

2 голосов
/ 21 февраля 2012

Это ожидаемое поведение для SO_REUSEADDR в сокете UDP. Удалите этот параметр, чтобы вернуться к нормальным правилам распределения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...