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

推荐订阅源

Hacker News - Newest:
Hacker News - Newest: "LLM"
S
SegmentFault 最新的问题
The Cloudflare Blog
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
P
Privacy & Cybersecurity Law Blog
有赞技术团队
有赞技术团队
www.infosecurity-magazine.com
www.infosecurity-magazine.com
雷峰网
雷峰网
Google DeepMind News
Google DeepMind News
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
The Hacker News
The Hacker News
人人都是产品经理
人人都是产品经理
阮一峰的网络日志
阮一峰的网络日志
大猫的无限游戏
大猫的无限游戏
L
Lohrmann on Cybersecurity
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
W
WeLiveSecurity
T
Threat Research - Cisco Blogs
博客园 - 叶小钗
量子位
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Simon Willison's Weblog
Simon Willison's Weblog
I
Intezer
S
Secure Thoughts
V
V2EX
Apple Machine Learning Research
Apple Machine Learning Research
小众软件
小众软件
酷 壳 – CoolShell
酷 壳 – CoolShell
Microsoft Azure Blog
Microsoft Azure Blog
博客园_首页
Help Net Security
Help Net Security
爱范儿
爱范儿
C
Cybersecurity and Infrastructure Security Agency CISA
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
腾讯CDC
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
Check Point Blog
WordPress大学
WordPress大学
Last Week in AI
Last Week in AI
T
Tor Project blog
NISL@THU
NISL@THU
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
I
InfoQ
The Register - Security
The Register - Security
Recent Announcements
Recent Announcements
N
News and Events Feed by Topic
B
Blog RSS Feed

逸思杂陈

家用网络 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)

参考