套接字中SO_REUSEPORT和SO_REUSEADDR

Q

可否多个进程监听同一个端口

A

可通过两种方式在同一个端口上监听

  • 设置 SO_REUSEPORT
  • 设置 SO_REUSEADDR

SO_REUSEPORT

测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import socket
import os
SO_REUSEPORT = 15
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
s.bind(('', 10000))
s.listen(1)
while True:
conn, addr = s.accept()
print "Connected to %d \t addr: %s " % (os.getpid(),addr)
#data = conn.recv(1024)
conn.send('Connected to {} \n'.format(os.getpid()))
conn.close()

这个参数在 MacOS 和 Linux 上被设置后,效果是不一样的。

在 MacOS 上的效果

  • 能无冲突的开启两个不同的进程


其中PID 23601 是第一个开启,PID 23696 是第二个开启的。

  • 使用nc去连接该端口


可以看到 只有 PID 23601 的socket 被连接
只有在kill 掉 PID 23601PID 23696 才会被连接

  • 并且可以在不同用户下运行该程序


接入顺序还是和前面的相同,先开启的进程会去接受请求,后开启的进程只有在先开启的进程结束后才能接受请求。

在Linux上的效果

  • 与MacOS不同之处在于,Linux 会随机(可能是某种算法)选择进程去接受请求。


    这样的好处是,上层程序可以将负载均衡完全交给系统层去完成。

  • 在用不同账户去尝试运行这个程序时会报错

这符合参考文档中的说明,linux 可以让多进程重用端口,但是这些进程必须是同一个账户。显然 Mac OS 的相关机制不同。

另外

参考文档中说 SO_REUSEPORT 是在Linux 3.9 之后加入的。
我的实验环境的内核版本为2.6

学校网关用的是 NAT 而不是 NAPT 只对 IP 地址进行了转换,端口号不变

reference

http://blog.csdn.net/Yaokai_AssultMaster/article/details/68951150
https://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t
https://bg2bkk.github.io/post/SO_REUSEADDR%E5%92%8CSO_REUSEPORT/