惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
Spread Privacy
Spread Privacy
S
Securelist
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Project Zero
Project Zero
G
GRAHAM CLULEY
Stack Overflow Blog
Stack Overflow Blog
爱范儿
爱范儿
Scott Helme
Scott Helme
S
Security Affairs
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
博客园_首页
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
T
The Exploit Database - CXSecurity.com
The Hacker News
The Hacker News
雷峰网
雷峰网
N
News and Events Feed by Topic
宝玉的分享
宝玉的分享
O
OpenAI News
小众软件
小众软件
C
Cybersecurity and Infrastructure Security Agency CISA
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
I
Intezer
Martin Fowler
Martin Fowler
S
Security @ Cisco Blogs
A
Arctic Wolf
Engineering at Meta
Engineering at Meta
U
Unit 42
L
Lohrmann on Cybersecurity
Google Online Security Blog
Google Online Security Blog
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
WordPress大学
WordPress大学
M
MIT News - Artificial intelligence
Schneier on Security
Schneier on Security
V2EX - 技术
V2EX - 技术
IT之家
IT之家
The Register - Security
The Register - Security
T
Tailwind CSS Blog
GbyAI
GbyAI
量子位
人人都是产品经理
人人都是产品经理
Recorded Future
Recorded Future
W
WeLiveSecurity
AWS News Blog
AWS News Blog
B
Blog RSS Feed
腾讯CDC
Hacker News - Newest:
Hacker News - Newest: "LLM"
Microsoft Security Blog
Microsoft Security Blog

逸思杂陈

家用网络 vlan 单线复用 Linux 平台 intel UHD 6xx 核显 openvino 探索 UI 区域检测的 vibe coding 复盘 mitmproxy 使用 esim 使用相关 阻止 bilibili 网页自动关注 Hexo 版本更新与技术债务 配置 Linux 作为主力操作系统 在 Linux 虚拟机中使用 PyAutoGUI 做自动化 语言的力量 联想笔记本 BIOS 跳过检测强制降级 redroid “设备未获得play保护机制认证” 问题 在 iOS 上访问安卓应用 在 VSCode 中用 Rust 刷LeetCode 跨域的那些事 HomeBrew 与无 root 权限 Linux 环境包管理 给 macOS 词典增加生词本功能 容器内进程优雅退出 Python 循环变量泄露与延迟绑定 bash 语法备忘 MySQL 自定义数据库路径
关闭子进程打开的文件描述符
Jay.Run · 2022-08-30 · via 逸思杂陈

我们在测试代码时,由于需要经常重启服务,经常会发现服务端口被占用。
一般kill掉后台进程就ok了,但是如果服务有启动一些常驻的后台程序,可能也会导致端口不能释放。

在类UNIX系统中,一切被打开的文件、端口被抽象为文件描述符(file descriptor)
从python3.4开始,文件描述符默认是non-inheritable,也就是子进程不会共享文件描述符。

问题

一般为了实现多进程、多线程的webserver,服务端口fd必须设置为继承(set_inheritable),这样才能多进程监听一个端口(配合SO_REUSEPORT)
典型的是使用flask的测试服务器的场景,这里我们写一段代码模拟。

1
2
3
4
5
6
import socket, os
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('127.0.0.1', 22222))
server.set_inheritable(True)

os.system("python -c 'import time;time.sleep(1000)' ")

我们通过lsof -p {pid}可以看到这两个进程的所有文件描述符
server进程, 可以看到服务端口的fd是4

1
2
3
4
5
6
7
8
9
10
11
COMMAND   PID  FD      TYPE             DEVICE  SIZE/OFF       NODE NAME
ptpython 6214 cwd DIR 253,0 4096 872946898 /
...
ptpython 6214 0u CHR 136,13 0t0 16 /dev/pts/13
ptpython 6214 1u CHR 136,13 0t0 16 /dev/pts/13
ptpython 6214 2u CHR 136,13 0t0 16 /dev/pts/13
ptpython 6214 3r CHR 1,9 0t0 2057 /dev/urandom
ptpython 6214 4u sock 0,7 0t0 58345077 protocol: TCP
ptpython 6214 5u a_inode 0,10 0 8627 [eventpoll]
ptpython 6214 6u unix 0x0000000000000000 0t0 58368029 socket
ptpython 6214 7u unix 0x0000000000000000 0t0 58368030 socket

sleep子进程,也拥有fd=4的文件描述符

1
2
3
4
5
6
7
COMMAND   PID  FD   TYPE DEVICE  SIZE/OFF       NODE NAME
python 18022 cwd DIR 253,0 4096 872946898 /
...
python 18022 0u CHR 136,13 0t0 16 /dev/pts/13
python 18022 1u CHR 136,13 0t0 16 /dev/pts/13
python 18022 2u CHR 136,13 0t0 16 /dev/pts/13
python 18022 4u sock 0,7 0t0 58345077 protocol: TCP

如果server进程退出时,sleep进程没有退出,fd=4对应的端口就被占用了,服务也就不能正常启动了。

解决方法

手动清理

1
2
3
4
5
6
7
8
import os
import time

os.system(f'lsof -p {os.getpid()}')
os.closerange(3, 100)
time.sleep(5)
os.system(f'lsof -p {os.getpid()}')

使用close_fds

使用subprocess库而不是os来启动子程序, 通过close_fds参数关闭多余的文件描述符

1
2
import subprocess
subprocess.call("python -c 'import time;time.sleep(1000)'", shell=True, close_fds=True)

参考