大部分内容来自stackoverflow上的回答:Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems?
    由于现有的操作系统上的socket都来自BSD socket,且每种操作系统都后续进行了相应的改变。下面先说 BSD socket中的行为,在最后一节单独介绍linux系统下的socket特定行为。

socket五元组

一个连接由五元组(src_ip, src_port, protocol, dst_ip, dst_port)来唯一确定,系统通过tcp/udp报头+IP报头中的这些信息来确定数据包来自远端的哪个进程,以及数据包是发往本地的哪个进程。
    对应到socket编程,一个连接由本地和远端的两个socket来确定。
    socket通过bind()指定本地使用的ip和端口(如果没有bind,对于udp或tcp客户端系统会随机分配);tcp客户端使用
connect()连接到远端的ip和端口,tcp服务器通过accept()获得远端的ip和端口,无连接的udp,通过udp报文获得远端的ip和端
口,有连接的udp,通过connect()来确定远端的ip和端口。

任意端口和IP


socket进行bind()操作时,可以指定“任意”ip或端口,其中“任意”ip指系统可选择本机上所有网卡上的ip,或者127.0.0.1(系统
会根据本地到对端之间的路由来合理选择使用哪个网卡上的ip,或127.0.0.1);“任意”端口是指让系统来随机选择一个可用的端口。

TIME_WAIT 和 Linger time

一个socket有一个发送缓冲区,当调用send()函数成功后,这并不意味着所有数据都真正被发送出去了,它只意味着数据都被送到了发送缓冲区中。对 于UDP socket来说,如果不是立刻发送的话,数据通常也会很快的发送出去,但对于TCP socket,在数据加入到缓冲区和真正被发送出去之间的时延会相当长。这就导致当我们close一个TCP socket的时候,可能在发送缓冲区中保存着等待发送的数据(由于send()成功返回,因此你也许认为数据已经被发送了)。
    所以当我们close一个TCP socket的时候,如果它仍然有数据等待发送,那么该socket会进入TIME_WAIT状态。这种状态将持续到数据被全部发送或者发生超时。
    在内核彻底关闭socket之前等待的总时间(不管是否有数据在发送缓冲区中等待发送)叫做Linger Time。Linger
Time在大部分系统上都是一个全局性的配置项而且在默认情况下时间相当长(在大部分系统上是两分钟)。socket选项SO_LINGER可以设置
Linger time,但强烈不建议这样做。

SO_REUSEADDR

由 于Linger time的存在,当我们close一个TCP socket A之后,再用另一个socket B去bind相同的ip和port,就会出现 EADDRINUSE 错误。这是对socket B在bind之前先去设置 SO_REUSEADDR,就可以绑定成功。注意:谁要去bind,就是谁去设置 SO_REUSEADDR。
 注意,SO_REUSEADDR 只有在socket A close之后,对socket B 设置 SO_REUSEADDR 选项,然后bind才能成功;如果socket A 先bind,然后socket B 在socket 没有close时就bind到相同的端口和ip,仍然会出错! 由于“任意”ip和端口的存在,如何判断两个ip+端口是否相同情况就比较复杂,具体如下表所示(socket A先bind,在未close之前socket B bind,结果):

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
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
ON/OFF 0.0.0.0:21 0.0.0.0:21 Error (EADDRINUSE)
SO_REUSEPORT

SO_REUSEADDR 并不能使两个socket同时使用本地相同的ip和端口,SO_REUSEPORT可以实现这个目的。
    为了实现多个socket同时使用相同的ip和端口,要求所有这些socket在bind之前都设置SO_REUSEPORT选项。

connect出现EADDRINUSE错误


果对端有多个socket同时绑定了相同的ip IP1和端口PORT1,如果本地有socket A 和 B都绑定在了相同的本地ip IP2和端口
PORT2,那么socket A 先connect 到对端的(IP1, PORT1),然后socket B再connect到对端的(IP1,
PORT1),则会出现 EADDRINUSE错误,因为这是 connection 五元组出现了重复。

多播

对 多播地址来说,SO_REUSEADDR的含义发生了改变,因为它允许多个socket绑定到完全一样的多播地址和端口,也就是说,对多播地址 SO_REUSEADDR的行为与SO_REUSEPORT对单播地址完全一样。事实上,对于多播地址,对SO_REUSEADDR和 SO_REUSEPORT的处理完全一样,对所有多播地址,SO_REUSEADDR也就意味着SO_REUSEPORT。

linux的 SO_REUSEADDR 和 SO_REUSEPORT

在linux 3.9之前,只存在选项SO_REUSEADDR。且该选项的行为大体上与BSD一样,除了两个差别:
(1)当一个监听(listening)TCP
socket绑定到通配地址和一个特定的端口,无论其它的socket或者是所有的socket(包括监听socket)都设置了
SO_REUSEADDR,其它的TCP
socket都无法绑定到相同的端口(BSD中可以),就更不用说使用一个特定地址了。这个限制并不用在非监听TCP
socket上,当一个监听socket绑定到一个特定的地址和端口组合,然后另一个socket绑定到通配地址和相同的端口,这样是可行的。
(2)当把SO_REUSEADDR用在UDP socket上时,它的行为与BSD上SO_REUSEPORT完全相同,因此两个UDP socket只要都设置了SO_REUSEADDR,那么它们可以绑定到相同的地址和端口。
    Linux 3.9加入了SO_REUSEPORT。这个选项允许多个socket(TCP or
UDP)不管是监听socket还是非监听socket只要都在绑定之前都设置了它,那么就可以绑定到完全相同的地址和端口。为了阻止"port
劫持"(Port hijacking)有一个特别的限制:所有希望共享源地址和端口的socket都必须拥有相同的有效用户id(effective user ID)。因此一个用户就不能从另一个用户那里"偷取"端口
    另外,内核在处理SO_REUSEPORT socket的时候使用了其它系统上没有用到的"特别魔法":
对于UDP
socket,内核尝试平均的转发数据报,对于TCP监听socket,内核尝试将新的客户连接请求(由accept返回)平均的交给共享同一地址和端口
的socket(监听socket)。这意味着在其他系统上socket收到一个数据报或连接请求或多或少是随机的,但是linux尝试优化分配。
例如:一个简单的服务器程序的多个实例可以使用SO_REUSEPORT socket实现一个简单的负载均衡,因为内核已经把复制的分配都做了。

SO_REUSEADDR 和 SO_REUSEPORT的更多相关文章

  1. SO_REUSEADDR和SO_REUSEPORT异同

    文章内容来源于stackoverflow上的回答,写的很详细http://stackoverflow.com/questions/14388706/socket-options-so-reuseadd ...

  2. SO_REUSEADDR与SO_REUSEPORT平台差异性与测试

    前些天,与另外一个项目组的同事聊天的时候,谈到他遇到的一个有意思的BUG.在window上启动服务器,然后客户端连接的时候收到一些奇怪的消息,查证了,原来是他自己的另一个工具也在相同的地址上监听,客户 ...

  3. Linux下端口复用(SO_REUSEADDR与SO_REUSEPORT)

    freebsd与linux下bind系统调用小结:    只考虑AF_INET的情况(同一端口指ip地址与端口号都相同) freebsd支持SO_REUSEPORT和SO_REUSEADDR选项,而l ...

  4. C 中级 - SO_REUSEPORT 和 SO_REUSEADDR

    引言 - 问题由来 刚开始学习网络编程时候, 常听到一个词, 先开启 "端口复用 SO_REUSEADDR". 那时很一知半解, 就知道该那么写了. 心里一直有些奇怪, 语义不通呀 ...

  5. 浅析套接字中SO_REUSEPORT和SO_REUSEADDR的区别

    Socket的基本背景 在讨论这两个选项的区别时,我们需要知道的是BSD实现是所有socket实现的起源.基本上其他所有的系统某种程度上都参考了BSD socket实现(或者至少是其接口),然后开始了 ...

  6. socket常见选项之SO_REUSEADDR,SO_REUSEPORT

    目录 SO_REUSEADDR time-wait SO_REUSEPORT SO_REUSEADDR 一般来说,一个端口释放后会等待两分钟之后才能再被使用,SO_REUSEADDR是让端口释放后立即 ...

  7. 套接字选项 之 SO_REUSEADDR && SO_REUSEPORT

    说明 本文下面内容基本上是截取自stackoverflow,针对这两个选项,在另外一篇文章中做了总结,请移步<Linux TCP套接字选项 之 SO_REUSEADDR && S ...

  8. setsockopt中参数之SO_REUSEADDR的意义(转)

    转  http://www.cnblogs.com/qq78292959/archive/2013/01/18/2865926.html setsockopt中参数之SO_REUSEADDR的意义(转 ...

  9. linux socket中的SO_REUSEADDR

    Welcome to the wonderful world of portability... or rather the lack of it. Before we start analyzing ...

随机推荐

  1. 实现LUT

    //实现LUT 查找表 #include "stdafx.h" #include <iostream> #include <opencv2/opencv.hpp& ...

  2. wpf的研究和反思

    WPF的研究和反思 目前是否适合使用wpf      WPF(Windows Presentation Foundation)是微软推出的基于Windows Vista的用户界面框架,属于.NET F ...

  3. JAVA基础知识之网络编程——-基于TCP通信的简单聊天室

    下面将基于TCP协议用JAVA写一个非常简单的聊天室程序, 聊天室具有以下功能, 在服务器端,可以接受客户端注册(用户名),可以显示注册成功的账户 在客户端,可以注册一个账号,并用这个账号发送信息 发 ...

  4. HDU(1175),连连看,BFS

    题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1175 越学越不会,BFS还是很高级的. 连连看 Time Limit: 20000/100 ...

  5. 通用的linux下安装配置svn独立服务

    参考资料: http://www.blogjava.net/zhouf/articles/251476.html http://www.cnblogs.com/thinksasa/archive/20 ...

  6. linux 强大的编辑器之vi

    vi编辑器是一个处理ASCII数据的文本工具.大多数linux发行版都已经默认安装了vi编辑器.vi是visual interface的缩写vim是 visual interface improved ...

  7. Java 常用排序算法/程序员必须掌握的 8大排序算法

    Java 常用排序算法/程序员必须掌握的 8大排序算法 分类: 1)插入排序(直接插入排序.希尔排序) 2)交换排序(冒泡排序.快速排序) 3)选择排序(直接选择排序.堆排序) 4)归并排序 5)分配 ...

  8. RS485模块(485与TTL信号的转换)

    1 综述 MAX3483, MAX3485, MAX3486, MAX3488, MAX3490以及MAX3491是用于RS-485与RS-422通信的3.3V,低功耗收发器,每个器件中都具有一个驱动 ...

  9. 复旦大学2013--2014学年第一学期(13级)高等代数I期末考试第七大题解答

    七.(本题10分)设 \(A\) 为数域 \(K\) 上的 \(n\) 阶非异阵, 证明: 对任意的对角阵 \(B\in M_n(K)\),  \(A^{-1}BA\) 均为对角阵的充分必要条件是 \ ...

  10. HDU1757 A Simple Math Problem 矩阵快速幂

    A Simple Math Problem Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...