大部分内容来自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. java 导入自定义类

    eclipse导入很容易,昨天上课学了一下用记事本写java,导入自定义类,这就麻烦了. 代码贴一下,方便操作: package tom.jiafei; public class SquareEqua ...

  2. Linux 性能监测:介绍

    看了某某教程.读了某某手册,按照要求改改某某设置.系统设定.内核参数就认为做到系统优化的想法很傻很天真:)系统优化是一项复杂.繁琐.长期的 工作,优化前需要监测.采集.测试.评估,优化后也需要测试.采 ...

  3. php中一个"异类"语法: $a && $b = $c;

    php中一个"异类"语法: $a && $b = $c;     $a = 1;$b = 2;$c = 3;$a && $b = $c;echo & ...

  4. Java内存模型--JMM简介

    JMM:Java Memory Model(Java内存模型),围绕着在并发过程中如何处理可见性.原子性.有序性这三个特性而建立的模型. 可见性:JMM提供了volatile变量定义,final.sy ...

  5. 如何使用NUnit

    http://www.c-sharpcorner.com/UploadFile/84c85b/nunit-with-C-Sharp/ 从github上下载安装包 NUnit.3.4.1.msi htt ...

  6. Systematic LncRNA Classification

    Systematic LncRNA Classification From: http://www.arraystar.com/Services/Services_main.asp?ID=307 An ...

  7. Django serializers 序列化 rest_framework

    参考官方文档1(你懂的):http://www.django-rest-framework.org/api-guide/serializers/ 参考官方文档2(你懂的):http://www.dja ...

  8. wooyunAPI

    经常要爬去乌云的信息,但是每次都是硬爬,写完了发现乌云有提供API的,整理给大家: 1. WooYun Api是什么 通过WooYun开放的Api接口,其它网站或应用可以根据自己获取的权限调用WooY ...

  9. 迷你sql profile,给缺少sql跟踪的朋友们

    如果你的数据库没有sqlprofile,看这里. 如果你没时间装sqlserver那一系列的东西,看看这里,也许能解决呢. 这是一个迷你版的sqlprofile ,在win7下测试,链接sqlserv ...

  10. FZU 2214 Knapsack problem(背包问题)

    Description 题目描述 Given a set of n items, each with a weight w[i] and a value v[i], determine a way t ...