Python Socket服务关闭SSH连接后无法正常工作问题咨询
SSH断开后后台运行的Python Socket网关服务失效问题
问题描述
- 基于Python开发Socket网关服务,用于接收车载定位器上报的数据包
- 在Windows端通过CMD连接AWS服务器,执行启动命令
python3 filename.py &启动服务:保持SSH连接开启时服务可正常运行,但服务打印内容仍会输出到SSH终端,与「命令末尾加&将进程放入后台、不向当前终端输出内容」的预期不符 - 核心故障:关闭SSH连接后重新登录服务器,执行
ps -axf python3可看到对应进程仍在运行,但服务已无法正常工作 - 故障细节:保持SSH连接不关闭时,程序可正常进入
listenToClient方法内的while True循环处理车载设备上报的数据包;关闭SSH连接后,即使进程存活,也无法进入该循环执行处理逻辑,初步判断问题不在业务代码层面 - 临时规避方案:通过tmux新建会话,在会话内执行Python脚本可正常运行,需要明确故障根本原因
核心代码片段
import socket import threading class ThreadedServer(object): def __init__(self, host, port): self.host = host self.port = port self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.sock.bind((self.host, self.port)) def listen(self): global connecteds connecteds = {} compareTimeConnecteds() self.sock.listen() while True: client, address = self.sock.accept() client.settimeout(60*5) threading.Thread(target = self.listenToClient,args = (client,address)).start() def listenToClient(self, client, address): bufferSize = 4096 while True: # 省略车载定位器数据包处理业务逻辑 pass if __name__ == "__main__": ThreadedServer('',port).listen()
根本原因
该故障由Linux会话信号机制、后台进程的绑定规则导致,与Python业务代码无关:
- 对
&符号的作用认知错误:命令末尾加&仅会将进程放入当前Shell的后台作业队列,不会让进程脱离当前SSH会话的控制,也不会自动断开进程与当前终端的标准输入、标准输出、标准错误绑定。这就是服务日志仍输出到SSH终端的原因——进程始终和当前SSH会话强关联。 - SIGHUP信号导致进程进入僵死状态:关闭SSH连接时,系统会向当前会话关联的所有进程(包括
&启动的后台进程)发送SIGHUP(挂断信号)。绝大多数Python服务会通过print打印运行日志,SSH断开后终端对应的标准输出文件描述符失效,print操作会触发BrokenPipeError异常。由于代码没有做全局异常捕获,主线程的accept监听循环会直接终止,但已创建的工作子线程未被系统回收,就会出现ps能查到进程ID存在、但服务无法接收处理新请求的现象。 - tmux规避问题的原理:tmux会在服务器后台维持独立的伪终端会话,会话生命周期不与SSH连接绑定,会话内运行的进程不会收到SSH断开触发的
SIGHUP信号,因此可以持续正常运行。
推荐的长期运行启动方式
如果不依赖tmux/screen这类终端复用工具,可选择以下两种生产环境常用方案:
- 临时启动:使用
nohup忽略SIGHUP信号,同时重定向输出避免IO错误,命令为nohup python3 filename.py > service.log 2>&1 &,日志将写入当前目录的service.log文件,不会输出到终端 - 生产部署:编写systemd服务配置文件托管进程,可配置服务开机自启、异常自动重启、日志统一收集,是长期运行服务的标准方案
内容的提问来源于stack exchange,提问作者Guilherme Londero
相关产品推荐
相关产品推荐

