40-TCP 多进程共享 socket

tornado 源码多进程(process.py)那段,发现他的多进程模型和一般常见的模型有点不一样,

  • 常见的是主进程 bind -> listen -> accept, 将 accept 返回的 socket 用子进程处理,
  • tornado 则是 bind -> listen -> fork, 在 listen 之后 fork,多个子进程共享 listen socket,每个子进程都 accept。

感觉会有错误或 “惊群” 现象,自己写了个程序测试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import socket
import select
import os
import time
import errno

def child_epoll():
epoll = select.epoll()
epoll.register(sock.fileno(), select.EPOLLIN)
try:
while True:
events = epoll.poll(1)
for fileno, event in events:
if fileno == sock.fileno():
connection, address = sock.accept()
print(os.getpid(), address)
time.sleep(1)
connection.close()
finally:
epoll.unregister(sock.fileno())
epoll.close()


def start_child(i):
pid = os.fork()
if pid == 0:
child_epoll()
else:
children[pid] = i

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.bind(("0.0.0.0", 9700))
sock.listen(128)


children = {}

for i in range(4):
start_child(i)

time.sleep(2)
print(children)
while children:
try:
pid = status = os.wait()
except Exception as e:
if e.errno == errno.EINTR:
continue
raise
if pid not in children:
continue
children.pop(pid)

然后用 ab 测测:ab -n 10 -c 5 http://127.0.0.1:9700/

可以发现每个连接都会只有一个进程去处理。虽然逻辑上没有错误,

http://static.usenix.org/event/usenix2000/freenix/full_papers/molloy/molloy.pdf 该论文说linux 2.6内核之后accept不会有惊群现象

Reference


40-TCP 多进程共享 socket
https://flepeng.github.io/010-network-40-传输层-40-TCP-多进程共享-socket/
作者
Lepeng
发布于
2024年9月23日
许可协议