如何绑定到任何可用端口?

66

我需要一个应用程序来向某个网络服务器发送UDP数据包并接收响应。服务器将回复到与请求相同的端口号,因此我首先需要将我的套接字绑定(bind)到任何UDP端口号。

硬编码UDP端口号是不好的想法,因为它可能被运行在同一台电脑上的其他应用程序使用。

有没有办法将UDP套接字绑定到任何可用端口?在我看来,这应该是一种快速获取空闲端口号的有效方法,例如由accept()函数使用的端口号。

如果不能,那么最好的策略是尝试顺序绑定并检查WSAEADDRINUSE / EADDRINUSE状态:从1025开始顺序尝试端口、或者从1025+rand()开始随机尝试端口号,还是其他策略?


1
accept() 函数用于基于连接的套接字,而不是数据报套接字。 - Beano
1
也许这会有所帮助:http://serverfault.com/questions/447044 - yegor256
在POSIX中,还需要范围1024+:https://dev59.com/OHNA5IYBdhLWcg3wjOve - Ciro Santilli OurBigBook.com
3个回答

281

另一个选择是在 bind() 中指定端口为0。这将允许您绑定到特定的IP地址(如果您安装了多个)同时仍绑定到随机端口。如果您需要知道选择了哪个端口,可以在绑定完成后使用 getsockname()


36
绑定到端口0是绑定到操作系统随机分配端口的官方文档记录方式。 - Remy Lebeau
11
bind()文档中提到:如果端口号指定为0,则服务提供程序将从动态客户端端口范围内分配一个唯一的端口给该应用程序。在Windows Vista及更高版本中,动态客户端端口范围的值为49152到65535。这与Windows Server 2003及更早版本不同,后者的动态客户端端口范围的值为1025到5000。调用bind()函数后,应用程序可以使用getsockname函数来查询已分配给套接字的地址和端口号。 - Remy Lebeau
6
这个问题被标记为“Windows”和“WinSock”,所以我引用了Microsoft文档。据我所知,绑定到端口0在4.2BSD标准中有记录,平台实现是基于该标准的。 - Remy Lebeau
6
在Linux内核中,将端口号设置为0被视为请求随机分配端口号的一个普通操作,以至于它甚至没有在规范文档中进行说明。(见net/ipv4/inet_connection_sock.c, inet_csk_get_port函数) - fche
4
@hanshenrik Linux在请求端口0时记录了绑定到临时端口的行为。这种行为在https://man7.org/linux/man-pages/man7/ip.7.html中有描述。另请参阅https://man7.org/linux/man-pages/man2/bind.2.html中“EADDRINUSE”的描述。 - Remy Lebeau
显示剩余5条评论

47

如果在调用 bind 函数之前使用 sendto 函数,则该套接字将自动绑定到一个可用端口上。


5
隐式绑定也是绑定,对吧?在我看来,这两个答案都很有用。 - WGH
17
@claf,你的逻辑有点不合理。你因为题目发起者(完全是另一个人)的选择而给某个回答投了反对票。我同意Remy的回答更好,他得到了应得的赞,但仅仅因为另一个回答更好就投反对票是没有意义的。对于这次不公正的反对票,我给予该回答一枚加一。 - Hi-Angel
1
@Hi-Angel:当我匆忙时,我只是使用投票和反对票来“排序”答案,通常我会阅读被接受的答案并查看第一和第二个答案之间的投票差异(如果第二个答案比被接受的答案更有价值,那么它值得一读)。这就是我如何使用SO,至少我不会对自己不合逻辑。 - claf
1
@claf,至少你说出了原因。你在这里做得很好。在SO上有时会出现一些人只是进行负面评价,他们既没有大脑来解释原因,也可能只是懦夫。或者两者都有。你是个好人。 - Hi-Angel
1
@claf 点赞是因为你错了。两种技术都可以使用,而且这种方式可以节省 bind() 调用。不仅适用于 Windows。 - user207421
显示剩余2条评论

-1

我一定漏了什么,为什么不使用UDP套接字来发送数据? 从sendto开始,然后使用recvfrom函数读取传入的数据,同时您还可以获得数据发送地址的奖励,这样您就可以发送回应了。


有些协议要求您关注您端口号的使用。例如,TFTP客户端使用它来区分来自同一服务器的多个并发传输。服务器不能只从同一端口发送回复,每个文件传输都需要服务器从不同的源端口发送。但是,服务器确实按照您概述的方式回复客户端的源地址和端口。 - doug65536
1
在我的具体示例中,为每个传输使用一个新的套接字,然后盲目地执行 sendto 将隐式选择源端口,但可能存在其他协议,在实际执行 sendto 之前,您确实关心端口号将是什么。 - doug65536
@doug65536 这是一个有效的例子,但原始问题没有包含任何关于为什么的具体细节。 - Jonke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接