【问题标题】:Why does bind return the same ephemeral port?为什么 bind 返回相同的临时端口?
【发布时间】:2012-02-21 10:31:09
【问题描述】:

我有一个问题,我创建了两个 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 地址上的两个套接字,但端口不同。谁能解释为什么两个套接字共享同一个端口?任何人都可以提出解决方案吗?

【问题讨论】:

    标签: sockets udp


    【解决方案1】:

    这是 SO_REUSEADDR 在 UDP 套接字上的预期行为。删除该设置以恢复正常的分配规则。

    【讨论】:

    • 这不是 SO_REUSEADDR 选项。删除它意味着第二次绑定失败。您应该能够将两个 UDP 套接字绑定到同一个接口并具有不同的端口。
    • 我还应该提到,如果我将 fd2 的绑定移动到 fd1 的绑定下方,我会得到不同的端口。很奇怪。我无法解释这种行为。
    • 那是因为在你绑定 fd1 之后,你使用paddr 调用了getsockname()。因此,您的第二个绑定请求的端口号与分配给 fd1 的端口号相同。设置 SO_REUSEADDR 会导致它允许这样做,即使这不是你想要的。确保在第二次绑定之前重置 paddr。
    • 非常好 - 谢谢。既然有人向我指出了这一点,那就太简单了。
    猜你喜欢
    • 1970-01-01
    • 2013-10-21
    • 2015-08-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多