SO_REUSEADDR和SO_REUSEPORT套接字选项
from UNIX网络编程.卷1 P165~P167
SO_REUSEADDR套接字选项
SO_REUSEADDR套接字选项有4种不同作用:
1)SO_REUSEADDR允许启动一个监听服务器并捆绑well-known端口号(0~1023),即使之前将端口用作本地端口而建立的连接仍然存在。这种情形通常这样碰到:
a)启动一个监听服务器;
b)连接请求到达,派生一个子进程来处理这个客户;
c)监听服务终止,但子进程继续为现有连接上的客户端提供服务;
d)重启监听服务器;
默认情况下,当监听服务器在步骤d通过调用socket, bind, listen重新启动时,由于试图捆绑一个现有连接上的端口,bind调用会失败。但如果在调用socket和bind之间设置SO_REUSEADDR套接字选项,那么bind会成功。
所有TCP服务器都应该指定本套接字选项,以允许服务器在这种情形下被重新启动。
2)SO_REUSEADDR允许在同一端口上启动同一服务器的多个实例,只要每个实例捆绑一个不同的本地IP地址即可。这对于使用IP别名技术(一个网络接口多个IP地址的技术)托管多个HTTP服务器的网点(site)来说很常见。
例如,本地主机的主IP地址198.69.10.2, 有2个别名198.69.10.128, 198.69.10.129。在其上启动三个HTTP服务器:第一个以本地通配IP地址INADDR_ANY + 80端口调用bind;第二个以本地IP地址198.69.10.128 + 80端口调用bind;第三个以本地IP地址198.69.10.129 + 80端口调用bind。第二个、第三个HTTP服务器调用bind都会失败,除非在socket和bind之间利用setsockopt设置了SO_REUSEADDR选项。
注意:
(1)对于TCP,绝不可能启动捆绑相同IP地址和相同端口号的多个服务器:因为这是完全重复的捆绑(complete duplicate binding)。也就是说,IP地址198.69.10.128 + 80端口 ,不可能同时被两个服务器bind。即使设置了SO_REUSEADDR选项也没用。
(2)为了安全起见,有些操作系统不允许对已经绑定了通配地址(INADDR_ANY)的端口再捆绑任何“更为明确的”地址。也就是说,执行通配地址绑定的服务器进程,必须最后一个启动。
3)SO_REUSEADDR允许单个进程捆绑同一端口到多个套接字上,只要每次捆绑指定不同的本地IP地址即可。
4)SO_REUSEADDR允许完全重复的捆绑:当一个IP地址和端口已绑定到某个套接字上时,如果传输协议支持,同样的IP地址和端口还可以捆绑到另一个套接字上。一般来说,本特性仅支持UDP套接字。
SO_REUSEPORT 套接字选项
SO_REUSEPORT 于4.4BSD随多播支持引入。没有在SO_REUSEADDR上重载所需多播语义(即允许完全重复的捆绑),而是给SO_REUSEPORT引入以下语义:
1)SO_REUSEPORT允许完全重复的捆绑,不过只有在想要捆绑同一IP地址和端口的每个套接字都指定了本套接字选项才行。
2)如果被捆绑的IP地址是一个多播地址,那么SO_REUSEADDR和SO_REUSEPORT被认为是等效的。
注意:并非所有系统都支持SO_REUSEPORT套接字选项。那些不支持本选项,但支持多播的系统,改用SO_REUSEADDR以允许合理的完全重复的捆绑,即同一时刻在同一个主机上可运行多次且期待接收广播或多播数据报的UDP服务器。
总结
1)在所有TCP服务器程序中,调用bind之前都设置SO_REUSEADDR套接字选项;
2)编写一个可在同一个时刻在同一主机上运行多次的多播应用程序时,设置SO_REUSEPADDR套接字选项,并将所参加多播组的地址作为本地IP地址捆绑。
参考
[1] W.RichardStevens, BillFenner, AndrewM.Rudoff. UNIX网络编程.卷1,套接字联网API.volume 1,The sockets networking API[M]. 人民邮电出版社, 2010.
[2] https://stackoverflow.com/questions/14388706/how-do-so-reuseaddr-and-so-reuseport-differ/14388707#14388707