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

说明

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

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

man手册中对这两个套接字的描述
SO_REUSEADDR
SO_REUSEADDR
       Indicates  that  the  rules used in validating addresses supplied in a bind(2) call should allow reuse of local addresses.  For AF_INET
       sockets this means that a socket may bind, except when there is an active listening socket bound to the address.   When  the  listening
       socket  is bound to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address.  Argument is an
       integer boolean flag.

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

解释:

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

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

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

如下面表格所示:

已绑定                请求绑定              成功与否
------------------------------------------------
192.168.0.100:22345  192.168.0.100:22345  失败
192.168.0.100:22345  0.0.0.0:22345        失败
192.168.0.100:22345  192.168.0.101:22345  成功
0.0.0.0:22345        192.168.0.100:22345  失败
0.0.0.0:22345        0.0.0.0:22345        失败
  • 在启用SO_REUSEADDR选项,并且已绑定的连接处于非LISTEN状态,则可以重复绑定;这也是使用SO_REUSEADDR的主要作用,即服务器重启时,当已绑定连接处于TIME_WAIT状态时,允许重复绑定;上面表格列出的所有情况均可以绑定成功;
  • 补充:SO_REUSEADDR选项要求必须每个绑定到该端口的套接字都开启,这点与BSD有区别,BSD只要当前请求绑定的开启就可以;
SO_REUSEPORT
SO_REUSEPORT
      Permits multiple AF_INET or AF_INET6 sockets to be bound to an identical socket address.  This  option  must  be  set  on  each  socket
      (including  the  first  socket) prior to calling bind(2) on the socket.  To prevent port hijacking, all of the processes binding to the
      same address must have the same effective UID.  This option can be employed with both TCP and UDP sockets.

      For TCP sockets, this option allows accept(2) load distribution in a multi-threaded server to be improved by using a distinct  listener
      socket  for  each  thread.   This  provides  improved  load  distribution  as  compared  to  traditional techniques such using a single
      accept(2)ing thread that distributes connections, or having multiple threads that compete to accept(2) from the same socket.

      For UDP sockets, the use of this option can provide better distribution of incoming datagrams to multiple  processes  (or  threads)  as
      compared to the traditional technique of having multiple processes compete to receive datagrams on the same socket.

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

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

内核4.12.12中关于重用部分冲突检查的源码解析
1 if ((!reuse || !sk2->sk_reuse || sk2->sk_state == TCP_LISTEN)
2     && (!reuseport || !sk2->sk_reuseport || rcu_access_pointer(sk->sk_reuseport_cb)
3        || (sk2->sk_state != TCP_TIME_WAIT && !uid_eq(uid, sock_i_uid(sk2))))) {
4         if (inet_rcv_saddr_equal(sk, sk2, true))
5                     break;
6 }

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

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

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

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

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

原文地址:https://www.cnblogs.com/wanpengcoder/p/11750534.html

时间: 2024-10-29 00:06:23

Linux TCP套接字选项 之 SO_REUSEADDR && SO_REUSEPORT的相关文章

LINUX TCP套接字详细配置

提高服务器的负载能力,是一个永恒的话题.在一台服务器CPU和内存资源额定有限的情况下,最大的压榨服务器的性能,是最终的目的.要提高 Linux系统下的负载能力,可以先启用Apache的Worker模式,来提高单位时间内的并发量.但是即使这么做了,当网站发展起来之后,连接数过多 的问题就会日益明显.在节省成本的情况下,可以考虑修改Linux的内核TCP/IP参数,来最大的压榨服务器的性能.当然,如果通过修改内核参数也无法 解决的负载问题,也只能考虑升级服务器了,这是硬件所限,没有办法的事. Lin

linux程序设计——套接字选项(第十五章)

现在可以改进客户程序,使它可以连接到任何有名字的主机,这次不是连接到示例服务器,而是连接到一个标准服务,这样就可以演示端口号的提取操作了. 大多数UNIX和一些linux系统都有一项标准服务daytime,它提供系统的日期和时间.客户可以连接到这个服务来查看服务器的当前日期和时间.下面就是完成这一工作的客户程序getdate.c 编写程序getdate.c /*********************************************************************

TCP套接字端口复用SO_REUSEADDR

下面建立的套接字都是tcp套接字 1.进程创建监听套接字socket1,邦定一个指定端口,并接受了若干连接.那么进程创建另外一个套接口socket2,并试图邦定同一个端口时候,bind错误返回“Address already in use”(即使使用了SO_REUSEADDR). 2.进程创建监听套接字,邦定一个指定端口,并接受了若干连接,为每个连接创建子进程为连接服务.杀死监听套接字所在进程,然后重新启动.重新启动的进程调用bind重新建立监听套接字.这次邦定只有在bind前指定了SO_REU

Unix网络编程学习笔记之第7章 套接字选项

一.获取/设置套接字选项的方法 一个套接字描述符相关联的套接字选项很多.获取/设置套接字选项的方法: 1.  getsockopt和setsockopt函数 2. fcntl函数 3. ioctl函数 二. getsockopt和setsockopt函数 int getsockopt(int sockfd, int level, int optname, void* optval, socklen_t* optlen); int setsockopt(int sockfd, int level,

SO_REUSEADDR 套接字选项应用实例

网络上关于SO_REUSEADDR套接字选项用来解决地址重用问题的资料不少,但只停留在文字表达上,并没有实例,很容易误导初学者,并产生疑惑,此处不再赘述.下面通过一个简短的例子来展示如何在项目中合理的使用该选项,以及需要注意的问题. 关于TCP断开连接四次握手,如图所示 应用场景: 之前项目中遇到一个问题,聊天服务器的开启,关闭和重启,例如将服务器关闭后,实际上关闭了服务器的监听套接字(close),如果此时用户点击开启服务器,那么用户希望的情况是服务器又立即启动了.而由于close后,执行了主

linux netlink套接字实现类似ss命令 ,统计套接字以及TCP信息

参考了 ss的源代码 以及 netlink相关资料:http://blog.csdn.net/scdxmoe/article/details/27711205 实现结果为: gcc netlink_dig_530_7.c -o netlink_dig_530_7 ./netlink_dig_530_7 state      family     l.addr     l.port       r.addr     r.rport LISTEN     AF_INET   localhost  

套接字选项

套接字选项,超高级货,赛车的按钮盘 getsockopt和setsockopt 原型:int getsockopt(int s,int level,int opname,void *optval,socklen_t *optlen); 原型:int setsockopt(int s,int level,int optname,const void *optval,socklen_t optlen); s为将要获取或设置的套接字描述符,可以通过socket函数获取 level为选项所在的协议层 o

《网络编程》基于 TCP 套接字编程的分析

本节围绕着基于 TCP 套接字编程实现的客户端和服务器进行分析,首先给出一个简单的客户端和服务器模式的基于 TCP 套接字的编程实现,然后针对实现过程中所出现的问题逐步解决.有关基于 TCP 套接字的编程过程可参考文章<基本 TCP 套接字编程>.该编程实现的功能如下: (1)客户端从标准输入读取文本,并发送给服务器: (2)服务器从网络输入读取该文本,并回射给客户端: (3)客户端从网络读取由服务器回射的文本,并通过标准输出回显到终端: 简单实现流图如下:注:画图过程通信双方是单独的箭头,只

UNIX网络编程——套接字选项(心跳检测、绑定地址复用)(转)

/* 设置套接字选项周期性消息检测连通性 心跳包. 心博.主要用于长连接. * 参数:套接字, 1或0开启, 首次间隔时间, 两次间隔时间, 断开次数 */ void setKeepAlive( int iSockfd , int iSockAttrOn, socklen_t iIdleTime , socklen_t iInterval , socklen_t iCount ){ setsockopt( iSockfd , SOL_SOCKET , SO_KEEPALIVE , (const