【问题标题】:How to find local/epheremal port number?如何找到本地/临时端口号?
【发布时间】:2019-04-12 10:59:12
【问题描述】:

我有一个使用 Berkley 套接字和 Winsock(取决于平台)的 UDP 客户端程序。

基本上它使用getaddrinfo(),然后是socket(),然后是sendto()sendto() 获取getaddrinfo() 返回的地址信息。我的代码如下所示:

struct addrinfo hint;
memset(&hint, 0, sizeof(hint));
hint.ai_socktype = SOCK_DGRAM;
struct addrinfo *address;
getaddrinfo("127.0.0.1", "9999", &hint, &address);

SOCKET s = socket(address->ai_family, address->ai_socktype, address->ai_protocol);
sendto(s, "test", 4, 0, address->ai_addr, address->ai_addrlen);

我的问题是,本地/临时端口号何时设置?是否设置了对sendto() 的调用?如果我将更多数据发送到不同的服务器,sendto() 是否会重用相同的临时端口号?如何获取临时端口号(以独立于协议的方式)?我知道知道这可能没有用,而且 NAT 无论如何都可以改变它,但我只是想了解它是如何更好地工作的。

我也知道我可以使用bind() 设置本地端口,但我的问题是当操作系统为我选择本地端口时会发生什么。

【问题讨论】:

    标签: c sockets udp winsock berkeley-sockets


    【解决方案1】:

    你想要getsockname函数:

    struct sockaddr_storage ss;
    socklen_t len;
    
    len = sizeof(ss);
    if (getsockname(s, (struct sockaddr *)&ss, &len) == 0) {
        // print contents of ss
    }
    

    它使用套接字绑定到的地址和端口填充给定的sockaddr

    winsock 和 Berkely 套接字都提供此功能。

    【讨论】:

    • 我的问题是,什么时候设置本地/临时端口号?是否设置了对 sendto() 的调用?如果我将更多数据发送到不同的服务器,sendto() 是否会重用相同的临时端口号?
    • 另外,您的解决方案使用 sockaddr_in,它不适用于 IPv6。我怎样才能让它与 addrinfo 一起工作?
    • @mark 因为 UDP 套接字仅由源 IP/端口标识,所以在第一次发送时设置端口。至于sockaddr_in,我认为您可以使用sockaddr_storage 来代替保存IPv4 或IPv6 地址,虽然我没有尝试过。
    【解决方案2】:

    sendto() 的 MSDN 文档指出:

    注意如果打开了一个套接字,调用setsockopt,然后调用sendtoWindows 套接字执行一个隐式的bind 函数调用

    如果套接字未绑定,系统会为本地关联分配唯一值,然后将套接字标记为已绑定。如果套接字已连接,则可以使用getsockname 函数来确定与套接字关联的本地 IP 地址和端口。

    如果套接字未连接,getsockname 函数可用于确定与套接字关联的本地端口号,但返回的 IP 地址设置为给定协议的通配符地址(例如,INADDR_ANY或“0.0.0.0”表示 IPv4,IN6ADDR_ANY_INIT 或“::”表示 IPv6)。

    【讨论】:

      【解决方案3】:

      可以 bind 到端口 (0),这将导致操作系统找到一个开放的临时端口,您可以使用getsockname 发现该端口,或者返回EADDRINUSE甚至在你尝试发送任何东西之前。


      至于一个临时端口被操作系统分配,来自ip(7) Linux manual page

      [...] 一个临时端口被分配给下面的一个套接字 情况:

      • 当套接字地址中的端口号被指定为 0 时 打电话给bind(2)

      • listen(2) 在之前未绑定的流套接字上调用;

      • connect(2) 在以前没有的套接字上被调用 绑定;

      • sendto(2) 在先前未绑定的数据报套接字上调用。

      【讨论】:

        猜你喜欢
        • 2011-11-28
        • 2011-10-03
        • 2012-06-28
        • 1970-01-01
        • 1970-01-01
        • 2011-11-03
        • 2012-05-07
        • 1970-01-01
        相关资源
        最近更新 更多