1

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

基本上它使用getaddrinfo(), then socket(), then 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()用来设置本地端口,但我的问题是当操作系统为我选择本地端口时会发生什么。

4

3 回答 3

0

你想要的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 套接字都提供此功能。

于 2018-11-08T21:12:19.223 回答
0

MSDN 的sendto()状态文档:

注意 如果打开套接字,进行 setsockopt调用,然后进行 sendto 调用,Windows 套接字将执行隐式bind函数调用

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

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

于 2018-11-09T07:26:10.067 回答
0

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


至于操作系统何时分配临时端口,来自ip(7) Linux 手册页

[...] 在以下情况下,将临时端口分配给套接字:

  • 调用时将套接字地址中的端口号指定为0 bind(2)

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

  • connect(2)在先前未绑定的套接字上调用;

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

于 2018-11-09T07:29:28.227 回答