简介

记录一下stackoverflow关于 SO_REUSEPORT SO_REUSEADDR 两个选项的解释。

理论

SO_REUSEADDR

如果在绑定套接字之前在套接字上启用了SO_REUSEADDR,则可以成功绑定该套接字,除非与绑定到完全相同的源地址和端口组合的另一个套接字发生冲突。现在你可能想知道这和以前有什么不同?关键词是“完全正确”。因此,REUSEADDR主要改变了在搜索冲突时处理通配符地址(“任何IP地址”)的方式。

测试结果:

SO_REUSEADDR socketA socketB Result
ON/OFF 192.168.0.1:21 192.168.0.1:21 Error (EADDRINUSE)
ON/OFF 192.168.0.1:21 10.0.0.1:21 OK
ON/OFF 10.0.0.1:21 192.168.0.1:21 OK
ON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE)
OFF 0.0.0.0:21 192.168.1.0:21 Error (EADDRINUSE)
OFF 192.168.1.0:21 0.0.0.0:21 Error (EADDRINUSE)
ON 0.0.0.0:21 192.168.1.0:21 OK
ON 192.168.1.0:21 0.0.0.0:21 OK

套接字有一个发送缓冲区,如果对send()函数的调用成功,并不意味着请求的数据实际上已经发送出去,它只意味着数据已经添加到发送缓冲区。对于UDP套接字,数据通常会很快发送,如果不是立即发送,但是对于TCP套接字,在向发送缓冲区添加数据和让TCP实现真正发送数据之间可能会有相对较长的延迟。因此,当您关闭TCP套接字时,发送缓冲区中可能仍有挂起的数据,该数据尚未发送,但您的代码认为它已发送,因为send()调用已成功。如果TCP实现在您请求时立即关闭套接字,那么所有这些数据都将丢失,您的代码甚至不知道这一点。TCP被认为是一种可靠的协议,像这样丢失数据不是很可靠。这就是为什么当你关闭一个仍然有数据要发送的套接字时,它会进入一种称为TIME_WAIT的状态。在该状态下,它将等待所有挂起的数据成功发送,或者等待超时,在这种情况下,套接字将强制关闭。

内核在关闭套接字之前等待的时间量,不管它是否仍有数据在传输中,都称为延迟时间。在大多数系统上,延迟时间是全局可配置的,默认情况下相当长(在许多系统上,两分钟是一个常见值)。它还可以使用socket选项为每个socket配置,因此可以使用socket选项使超时更短或更长,甚至完全禁用超时。但是,完全禁用它是一个非常糟糕的主意,因为优雅地关闭TCP套接字是一个稍微复杂的过程,需要来回发送两个数据包(以及在数据包丢失时重新发送这些数据包),而整个关闭过程也受到延迟时间的限制。如果禁用“延迟”,套接字可能不仅会在传输过程中丢失数据,而且总是强制关闭而不是优雅地关闭,这通常是不推荐的。有关如何优雅地关闭TCP连接的详细信息超出了本回答的范围,如果您想了解更多信息,建议您查看本页。即使您禁用了延迟SO_LINGER,如果您的进程在没有明确关闭套接字的情况下死亡,BSD(可能还有其他系统)仍然会延迟,忽略您配置的内容。例如,如果您的代码只调用exit()(对于小型、简单的服务器程序来说非常常见),或者进程被信号终止(这包括它可能只是因为非法内存访问而崩溃)。因此,您无法确保套接字在任何情况下都不会出现。

问题是,系统如何处理状态为TIME_WAIT的套接字?如果未设置SO_REUSEADDR,则状态为TIME_WAIT的套接字仍被视为绑定到源地址和端口,任何将新套接字绑定到相同地址和端口的尝试都将失败,直到套接字真正关闭为止,这可能需要与配置的延迟时间一样长的时间。因此,不要期望在关闭套接字后可以立即重新绑定它的源地址。在大多数情况下,这将失败。但是,如果为您尝试绑定的套接字设置了SO_REUSEADDR,那么在TIME_WAIT状态下绑定到相同地址和端口的另一个套接字将被忽略,毕竟它已经“半死不活”,并且您的套接字可以绑定到完全相同的地址而不会出现任何问题。在这种情况下,另一个套接字可能具有完全相同的地址和端口并不起作用。请注意,如果另一个套接字仍在“工作”,则将套接字绑定到时间等待状态下与死亡套接字完全相同的地址和端口可能会产生意外的、通常是不希望的副作用,但这超出了本答案的范围,幸运的是,这些副作用在实践中相当罕见。

还有最后一件事你应该知道。只要要绑定到的套接字启用了地址重用,上面写的所有内容都可以工作。另一个套接字(已绑定或处于TIME_WAIT状态的套接字)在绑定时也不必设置此标志。决定绑定是成功还是失败的代码只检查馈入bind()调用的套接字的SO_REUSEADDR标志,对于所有其他已检查的套接字,甚至不查看该标志。

可以构造一个这样的测试,将SO_LINGER设置很长时间。开启SO_REUSEADDR,socketA发送数据并且关闭,socketB重新bind这个地址,应该是能成功的。

SO_REUSEPORT

所以,大多数人都会期望它会是这样。基本上,SO_REUSEPORT允许您将任意数量的套接字绑定到完全相同的源地址和端口,只要之前绑定的所有套接字在绑定之前也设置了SO_REUSEPORT。如果绑定到地址和端口的第一个套接字未设置SO_REUSEPORT,则在第一个套接字再次释放其绑定之前,任何其他套接字都不能绑定到完全相同的地址和端口,无论该其他套接字是否设置了SO_REUSEPORT。与SO_REUSEADDR的情况不同,处理SO_REUSEPORT的代码不仅会验证当前绑定的套接字是否设置了SO_REUSEPORT,而且还会验证具有冲突地址和端口的套接字在绑定时是否设置了SO_REUSEPORT

SO_REUSEPORT并不意味着SO_REUSEADDR。这意味着,如果一个套接字在绑定时没有设置SO_REUSEPORT,而另一个套接字在绑定到完全相同的地址和端口时设置了SO_REUSEPORT,则绑定会失败,这是预期的,但如果另一个套接字已经死亡并且处于TIME_WAIT状态,则绑定也会失败。为了能够在时间等待状态下将套接字绑定到与另一个套接字相同的地址和端口,需要在该套接字上设置SO_REUSEADDR,或者在绑定之前必须在两个套接字上都设置SO_REUSEPORT。当然,允许在套接字上同时设置SO_REUSEPORTSO_REUSEADDR

关于SO_REUSEPORT,除了它是在SO_REUSEADDR之后添加的之外,没有更多的内容可以说,这就是为什么在其他系统的许多套接字实现中找不到它,在添加此选项之前,它“分叉”了BSD代码,在此选项之前,无法将两个套接字绑定到BSD中完全相同的套接字地址。

实践

如何查看系统的版本

[root@test-qingzhou-01 ~]# hostnamectl
Static hostname: test-qingzhou-01
Icon name: computer-vm
Chassis: vm
Machine ID: 20190711105006363114529432776998
Boot ID: 2abf6a175d9e4dc4a16c0b28d262818b
Virtualization: kvm
Operating System: CentOS Linux 7 (Core)
CPE OS Name: cpe:/o:centos:centos:7
Kernel: Linux 3.10.0-957.21.3.el7.x86_64
Architecture: x86-64

相关代码

golang的代码

syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
setsockopt

参考

  • [1] StackOverflow-SO_REUSEPORT-SO_REUSEADDR
  • [2] SO_REUSEADDR和SO_REUSEPORT作用

REUSEPORT-REUSEADDR-学习相关推荐

  1. QVegas-一个升级版的TCP Vegas拥塞算法

    拥塞避免带来了很多疑惑,本文解开这个疑惑并给出一个实实在在但却很简陋的算法.         其实在基于丢包的拥塞算法中,拥塞避免的过程总是伴随着AI和MD的,不能光说AI而忽略MD.         ...

  2. tcp 端口复用与惊群效应(REUSEADDR、REUSEPORT)

    我在之前的一篇文章中,介绍了我在之前的项目中遇到的端口复用,windows 的udp里端口复用导致了一个bug,具体的链接参考如下: 关于Socket中端口复用_zhc的博客-CSDN博客_socke ...

  3. socket:REUSEADDR与REUSEPORT选项

    SO_REUSEADDR是创建socket时比较常用的选项,通过该选项让多个socket可以 bind相同的端口. 具体来说SO_REUSEADDR带来2个功能: 允许多个socket同时bind到相 ...

  4. Linux通讯架构服务器开发学习笔记

    第二课 环境搭建 1.安装vim sudo apt-get install vim-gtk 2.配置ip,网关,子网掩码 sudo vim /etc/network/interfaces 3.配置DN ...

  5. Fastsocket学习笔记之小结篇

    前言 前面啰啰嗦嗦的几篇文字,各个方面介绍了Fastsocket,盲人摸象一般,能力有限,还得继续深入学习不是.这不,到了该小结收尾的时候了. 缘起,内核已经成为瓶颈 使用Linux作为服务器,在请求 ...

  6. Linux Shell 编程学习总结

    Shell 教程 Shell简介:什么是Shell,Shell命令的两种执行方式 Shell本身是一个用C语言编写的程序,它是用户使用Unix/Linux的桥梁,用户的大部分工作都是通过Shell完成 ...

  7. 你们公司还没使用HTTP3?赶紧来补一补,学习一下如何在Nginx上配置HTTP3。

    你们公司还没使用HTTP3?赶紧来补一补,学习一下如何在Nginx上配置HTTP3. NGINX最新版本,已提供对 QUIC 和 HTTP/3的支持,本文介绍一下如何安装与配置 很高兴能在一个特殊的开 ...

  8. HTTP3快来了,提前学习一下如何在Nginx中支持HTTP3.0/QUIC

    HTTP3快来了,提前学习一下如何在Nginx中支持HTTP3.0/QUIC HTTP3.0,也称作HTTP over QUIC.核心是QUIC(读音quick)协议,由Google在2015年提出的 ...

  9. 【安全牛学习笔记】COCAT

    SOCAT 被称为nc++ (增强增强版的nc) - 双向数据流通道工具 连接端口 - Socat - tcp:1.1.1.1:80 侦听端口 - socat - tcp-listen:22 / so ...

  10. sofa源码学习----启动获取ServerConfig流程

    蚂蚁金服sofa rpc框架.公司想使用它作为架构的一部分,所以记录学习笔记. 1.从github下载源代码,版本为 5.6.0-SNAPSHOT,整个项目结构如下: 2.为了尽可能地只关注sofa ...

最新文章

  1. MYSQL 双主搭建
  2. 1060. [ZJOI2007]时态同步【树形DP】
  3. SPA单页应用前后分离微信授权
  4. MySQL语言的算法_MySQL知识整理
  5. php控件不显示,解决控件遮挡问题:关于有窗口元素和无窗口元素
  6. TensorFlow——多维矩阵的转置(transpose)
  7. 小白的奇幻数学课堂(part2)--敌人的敌人就是朋友,这其实就是负负得正法则
  8. node将图片转换成html文件,node+puppeteer将整个网页html转换为图片并保存【滚动截屏】...
  9. 如何伪装成一个彻头彻尾的程序员?
  10. 工程思想 ——【程序中的二进制】
  11. 查看文章strncpy()功能更好的文章
  12. ubuntu 下WebStorm 无法输入中文
  13. 福昕pdf Acrobat DC pdf 右键菜单注册表
  14. 201771010112罗松《面向对象程序设计(java)》第六周学习总结
  15. jzoj 3957 鸡腿の花园
  16. 数据采集系统有哪几种采集方式?
  17. 用计算机计算告白密码,阿拉伯数字高级表白密码 很火的表白密码
  18. 【Arduino】重生之Arduino 学僧(1)----Arduino简介
  19. 【TWVRP】遗传算法求解带时间窗的含充电站车辆路径规划问题【含Matlab源码 1177期】
  20. 【优化求解】基于自适应模拟退火粒子群优化算法求解单目标优化问题matlab代码

热门文章

  1. ag-grid 合并单元格(合并行)
  2. 社保系列6《账户划入交易》
  3. 24句经典哲理性语句
  4. 恒生o32系统介绍_南京证券向恒生发起会议:@宽途@O32@固收系统…
  5. 【问答机器人】QA机器人排序模型
  6. 5月新刊 | MDPI版面费将全面上涨,还有哪些期刊可投?(新增多领域高性价比新刊, 含CCF-B/SSCI/EI)~
  7. 如何从xp升级到WIN7
  8. Google发布手机街景地图
  9. N1盒子刷openwrt后刷安卓电视盒子、小钢炮、armbian的解决方法
  10. python学习面向对象Day09(P96~~106)