复用端口(SO_REUSEPORT)基本介绍
Linux kernel 3.9版本引入SO_REUSEPORT的新特性:
- 允许多个套接字 bind()/listen() 同一个TCP/UDP端口
- 内核层面实现负载均衡
解决了网络编程著名的惊群问题
代码
https://github.com/feelc/blogs-share/tree/main/0_multithread_server
为了多个线程可以绑定同一个IP和端口,则需要对socket进行如下的设置:
int32_t enable = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
启动后用netstat查看网络状态可以看到
5个线程同时监听了同一个TCP协议的IP和PORT,
5个线程同时监听了同一个UDP协议的IP和PORT。
# netstat -annp |egrep main |egrep 55555
tcp 0 0 127.0.0.1:55555 0.0.0.0:* LISTEN 3035124/./main
tcp 0 0 127.0.0.1:55555 0.0.0.0:* LISTEN 3035124/./main
tcp 0 0 127.0.0.1:55555 0.0.0.0:* LISTEN 3035124/./main
tcp 0 0 127.0.0.1:55555 0.0.0.0:* LISTEN 3035124/./main
tcp 0 0 127.0.0.1:55555 0.0.0.0:* LISTEN 3035124/./main
udp 0 0 127.0.0.1:55555 0.0.0.0:* 3035055/./main
udp 0 0 127.0.0.1:55555 0.0.0.0:* 3035055/./main
udp 0 0 127.0.0.1:55555 0.0.0.0:* 3035055/./main
udp 0 0 127.0.0.1:55555 0.0.0.0:* 3035055/./main
udp 0 0 127.0.0.1:55555 0.0.0.0:* 3035055/./main
测试
测试程序分10组请求,每组启动1000个客户端
#!/bin/bash
for (( i = 0; i < 10; i++ )); do
echo $i
for (( j = 0; j < 1000; j++ )); do
./client &
done
sleep 0.1
done
执行完毕后,观看服务端的输出:
tid: 0, cnt: 2058
tid: 1, cnt: 1996
tid: 2, cnt: 1917
tid: 3, cnt: 2008
tid: 4, cnt: 2021
服务端共有5个线程,可以看到每个线程处理的请求数相差不大,这就是内核负载均衡的效果。
内核负载均衡的实现原理请看连接