函数:
setsockopt
SO_REUSEADDR
:地址复用SO_REUSEPORT
:端口复用
一般来说,一个{addr,port}
只能被一个套接字绑定,即无法重用。
不同的套接字只能绑定到不同的{addr,port}
上!
示例
// sockfd_one, sockfd_two都要设置端口复用
// 在sockfd_one绑定bind之前,设置其端口复用
int opt = 1;
setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR, (const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
// 在sockfd_two绑定bind之前,设置其端口复用
opt = 1;
setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,(const void *)&opt, sizeof(opt) );
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
SO_REUSEADDR
功能如下:
- 若监听服务器进入TIME_WAIT状态,可立即重启
- 同一端口启动同一服务器的多个实例,需要每个实例套接字绑定不同的ip地址,一般需要多个网卡支持
- 支持完全重复的捆绑:
当一个IP地址和端口绑定到某个套接口上时,还允许此IP地址和端口捆绑到另一个套接口上。一般来说,这个特性仅在支持多播的系统上才有,而且只对UDP套接口而言(TCP不支持多播)。
对于监听线程来说,可重用套接字被称为监听桶(listener bucket),即每个套接字都是一个桶。
以event模型为例,假设目前有3个子进程,每个子进程中都有一个监听线程和多个工作线程。
- 端口未重用情况
在某一时刻,该监听套接字仅能由某一进程持有,当该进程接收到请求后,才让出监听权。
- 端口重用
- 2个监听桶
- 3个监听桶
3个监听桶下,各子进程均不用让出监听权,可以无限监听。
似乎看上去非常美好,性能好。不仅减轻了“监听权”(互斥锁)的争用,避免了“饥饿”;还能更高效的监听,实现负载均衡,从而减轻监听线程的压力。
但由于监听过程需要消耗CPU,若是单核CPU,无法体现出端口复用的优势,反而会由于切换监听线程而降低性能。
故若要使用端口复用,需要考虑如下:
- 是否将监听进程/线程隔离在各自CPU中
- 重用次数
- CPU核数