为了账号安全,请及时绑定邮箱和手机立即绑定

SO_REUSEADDR(setsockopt选项)-Linux是什么意思?

SO_REUSEADDR(setsockopt选项)-Linux是什么意思?

撒科打诨 2019-09-21 15:40:43
从手册页:SO_REUSEADDR指定在协议支持的情况下,用于验证提供给bind()的地址的规则应允许重用本地地址。此选项采用int值。这是一个布尔选项我什么时候应该使用它?为什么要“重用本地地址”?
查看完整描述

3 回答

?
桃花长相依

TA贡献1860条经验 获得超8个赞

TCP的主要设计目标是在遇到数据包丢失,数据包重新排序以及数据包复制(此处是关键)的情况下,实现可靠的数据通信。

在连接建立时,TCP / IP网络堆栈如何处理所有这些是相当明显的,但是在连接关闭之后会发生一种边缘情况。如果在会话结束时立即发送的数据包被复制并延迟,从而使4向关闭数据包在延迟的数据包之前到达接收器,会发生什么情况?堆栈会尽职地关闭其连接。然后,随后出现延迟的重复数据包。堆栈应该做什么?

更重要的是,如果在给定IP地址+ TCP端口组合上具有打开套接字的程序关闭其套接字,然后过一会儿,程序出现并希望监听相同的IP地址和TCP端口号,该怎么办? ?(典型情况:程序被杀死并迅速重启。)

有两种选择:

  1. 禁止重用该IP /端口组合至少2倍于数据包可以飞行的最大时间。在TCP中,这通常称为2x MSL延迟。有时您还会看到2× RTT,大致相等。

    这是所有常见TCP / IP堆栈的默认行为。2×MSL通常在30到120秒之间,并且在netstat输出中显示为TIME_WAIT周期。在那之后,堆栈假定由于TTL过期而在途中丢弃了任何恶意数据包,因此套接字离开了状态,从而允许重用IP /端口组合。TIME_WAIT

  2. 允许新程序重新绑定到该IP /端口组合。在具有BSD套接字接口的堆栈(实际上是所有Unix和类似Unix的系统,以及通过Winsock的 Windows)中,您必须在调用之前通过设置SO_REUSEADDR选项来询问这种行为。setsockopt()bind()

SO_REUSEADDR由于通常的使用模式是进行配置更改,因此通常在网络服务器程序中设置,因此需要重新启动该程序以使更改生效。如果不使用SO_REUSEADDR,则bind()在您杀死它时,如果先前实例的连接已打开,则在重新启动的程序的新实例中的调用将失败。这些连接会将TCP端口保持TIME_WAIT30-120秒的状态,因此您属于上述情况1。

设置的风险SO_REUSEADDR在于它会造成歧义:TCP数据包标头中的元数据不够独特,堆栈无法可靠地判断数据包是否陈旧,因此应丢弃该数据包而不是将其传递到新的侦听器套接字,因为显然是为即将死去的听众准备的。

如果您看不到这是真的,那么以下是侦听机的TCP / IP堆栈必须与每个连接配合使用才能做出的决定:

  1. 本地IP:每个连接都不唯一。实际上,这里的问题定义表示我们有意重用了本地IP。

  2. 本地TCP端口: Ditto。

  3. 远程IP:造成歧义的机器可以重新连接,因此不利于消除数据包的正确目的地。

  4. 远程端口:在行为良好的网络堆栈中,传出连接的远程端口无法快速重用,但只有16位,因此您有30-120秒的时间来迫使堆栈通过数万个选择并重用端口。在1960年代,计算机的工作速度很快。

    如果您的答案是远程堆栈应该TIME_WAIT在其侧面进行某些操作以禁止临时TCP端口重用,则该解决方案将假定远程主机是良性的。恶意参与者可以随意重用该远程端口。

    我想侦听器的堆栈可以选择仅严格禁止来自TCP 4元组的连接,以便在该TIME_WAIT状态期间阻止给定的远程主机与同一远程临时端口重新连接,但是我不知道任何具有那个特别的提炼。

  5. 本地和远程TCP序列号:这些序列号也不是唯一的,以至于新的远程程序无法提供相同的值。

如果我们今天要重新设计TCP,我想我们会将TLS或类似的东西集成为一项非可选功能,其作用之一是使这种无意和恶意的连接劫持成为不可能,但这需要添加大字段(128位及以上),这在1981年发布当时最新版本的TCP(RFC 793)的文档时还算不上实际。

如果不进行这种强化,则在允许TIME_WAIT您进行以下操作期间重新绑定所造成的歧义可以:a)将用于旧侦听器的陈旧数据错误地传递到属于新侦听器的套接字,从而破坏侦听器的协议或错误地将陈旧数据注入连接; 或b)错误地将新侦听器套接字的新数据分配给旧侦听器的套接字,因此无意中将其丢弃。

安全的做法是等待TIME_WAIT一段时间。

归根结底,这TIME_WAIT取决于成本选择:等待一段时间或承担不必要的数据丢失或意外数据注入的风险。

许多服务器程序会冒此风险,因此决定最好立即备份服务器,以免错过不必要的传入连接。

这不是一个普遍的选择。许多程序-甚至需要重新启动才能应用设置更改的服务器程序-都选择不做任何选择SO_REUSEADDR。程序员可能知道这些风险,并选择不采用默认设置,或者他们可能不知道问题所在,但正在从明智的默认设置中受益。

某些网络程序为用户提供了配置选项中的一个选择,从而使最终用户或sysadmin失去了责任。


查看完整回答
反对 回复 2019-09-21
?
手掌心

TA贡献1942条经验 获得超3个赞

创建套接字时,您并不是真正拥有它。操作系统(TCP堆栈)为您创建了它,并为您提供了一个句柄(文件描述符)来访问它。当您的套接字关闭时,操作系统要经历几个状态才能“完全关闭”它。正如EJP在评论中提到的,最长的延迟通常来自TIME_WAIT状态。为了在终止序列的最后处理边缘情况,并确保最后的终止确认通过或由于超时而使另一侧自行复位,需要额外的延迟来处理边缘情况。在这里,您可以找到有关此状态的一些其他注意事项。指出以下主要考虑因素:

请记住,TCP保证将尽可能传输所有传输的数据。当您关闭套接字时,服务器将进入TIME_WAIT状态,只是要真正确保所有数据都已通过。当套接字关闭时,双方通过相互发送消息达成协议,即他们将不再发送任何数据。在我看来,这已经足够好了,在完成握手之后,应该关闭插座。问题是双重的。首先,没有办法确保最后一个确认已成功通信。其次,网络上可能存在“游荡的重复项”,如果交付则必须处理。

如果您尝试快速创建具有相同ip:port对的多个套接字,则会收到“地址已在使用中”错误,因为较早的套接字不会被完全释放。使用SO_REUSEADDR将消除此错误,因为它将覆盖任何先前实例的检查。


查看完整回答
反对 回复 2019-09-21
  • 3 回答
  • 0 关注
  • 655 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信