Linux TCP套接字选项 之 SO_REUSEADDR && SO_REUSEPORT

说明

前面从stackoverflow上找了一篇讲这两个选项的文章,文章内容很长,读到最后对Linux中的这两个选项还是有些迷茫,所以重新写一篇文章来做一个总结;

本文只总结TCP单播部分,并且只讨论该选项的bind()系统调用部分,UDP,组播,开启选项之后数据包的调度等不做讨论;

man手册中对这两个套接字的描述
SO_REUSEADDR

原文简译:让bind()系统调用能够重用本地地址;对于AF_INET协议族的套接字来讲,除非有活动的监听套接字绑定到该地址,否则其他情况下可以重复绑定;如果一个监听套接字绑定到了通配地址INADDR_ANY,那么其他任何绑定到该端口的请求都是不允许的;

解释:

  • (1)不启用SO_REUSEADDR选项的情况下,或者(2)启用了SO_REUSEADDR选项但已绑定连接处于LISTEN状态下,任何重复绑定都不允许,包括:

(1) 如果原监听绑定是指定地址,则相同IP+相同端口,通配IP+相同端口不允许;但是不同IP+相同端口的绑定是允许的;

(2) 若果原监听绑定是通配地址,则任何向该端口的绑定都不可以;

如下面表格所示:

 

  • 在启用SO_REUSEADDR选项,并且已绑定的连接处于非LISTEN状态,则可以重复绑定;这也是使用SO_REUSEADDR的主要作用,即服务器重启时,当已绑定连接处于TIME_WAIT状态时,允许重复绑定;上面表格列出的所有情况均可以绑定成功;

 

  • 补充:SO_REUSEADDR选项要求必须每个绑定到该端口的套接字都开启,这点与BSD有区别,BSD只要当前请求绑定的开启就可以;

 

SO_REUSEPORT

原文简译:该选项允许完全相同地址重复绑定;需要重复绑定的每个套接字都要设置该选项,包括第一个;为了防止端口劫持,重复绑定必须是统一有效用户ID下的进程;在TCP服务器中,多个线程同时监听相同地址,则每个线程的accpet()调用会进行负载均衡,将请求进行平均分发;这与传统的套接字相比提供了更好的负载均衡,原方式比如单一线程accpet()来分发请求,或者多个accept()从一个套接字上竞争请求;

关于绑定,没有什么疑问,SO_REUSEADDR中列出表格中的地址都能绑定成功;

 

内核4.12.12中关于重用部分冲突检查的源码解析

源码解析,分以下四种情况:

未启用地址重用 && 未启用端口重用:检查冲突;

启用了地址重用 && 未启用端口重用:状态是LISTEN才检查冲突;

未启用地址重用 && 启用了端口重用:状态不是TIME_WAIT并且不是同一有效用户ID时,检查冲突;也就是说,假若是TIME_WAIT,则不需要检查;假如不是TIME_WAIT,但是有效用户ID相同,也不需要检查;

启用了地址重用 && 启用了端口重用:状态是LISTEN时,可能需要检查,需要继续判断端口重用,这时候只当有效用户ID不相同的时候,才需要检查;也就是说,可以相同用户ID的进程可以同时LISTEN多个相同的地址+端口;

本文链接:Linux TCP套接字选项 之 SO_REUSEADDR && SO_REUSEPORT

转载声明:转载请注明来源:Linux TCP/IP Stack,谢谢!


发表评论

电子邮件地址不会被公开。 必填项已用*标注