You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Ubuntu 22.04 LTS上稳定运行Python TCP监听器的有效方法

问题描述

我有一个监听4995端口的Python TCP脚本,需要它始终运行、监听连接并将接收的数据保存到文件中。脚本代码如下:

import socket
import threading
from datetime import datetime
import time


class Testing:
    def __init__(self):
        self.PORT = 4995
        self.SERVER = ''
        self.ADDR = (self.SERVER, self.PORT)
        self.count = 0
        

    def handle_client(self, conn, addr):
        print(f'[{datetime.now().strftime("%H:%M")}][NEW CONNECTION] {addr} connected.')
        s = time.time()
        while True:
            if time.time() - s > 300:
                conn.close()
                print(f'[{datetime.now().strftime("%H:%M")}][CLOSE CONNECTION] {addr} closed.')
                break
            try:
                msg = conn.recv(2048).decode('utf-8')
            except ConnectionResetError:
                print(f'[{datetime.now().strftime("%H:%M")}][CLOSE CONNECTION] {addr} closed by peers.')
                break
            else:
                if msg:
                    print(f'[{datetime.now().strftime("%H:%M")}] {msg}')
                    with open('msg.txt','a') as file:
                        file.write(msg)
                    s = time.time()

        # conn.close()

    def start(self):
        self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server.bind(self.ADDR)

        self.server.listen()
        print(f'[LISTENING] Server is listening on {self.SERVER}:{self.PORT}')
        while True:
            try:
                self.conn, addr = self.server.accept()
            except OSError:
                return
            thread = threading.Thread(target=self.handle_client, args=(self.conn, addr))
            thread.start()
            print(f'[{datetime.now().strftime("%H:%M")}][ACTIVE CONNECTIONS] {threading.active_count() - 1}')


if __name__ == '__main__':
    Testing().start()

我曾使用命令nohup python3 -u script.py &运行该脚本,初期可正常工作,但一段时间后客户端无法与服务器建立连接,而脚本本身仍在运行。经了解,nohup会因Linux系统资源情况导致脚本停止,现寻求让该脚本始终运行并监听连接的方法。

解决方案

一、先修复脚本潜在问题

脚本运行一段时间后无法接受新连接,不一定是nohup的问题,先排查并修复脚本本身的隐患:

  • 处理客户端的线程未设置为守护线程,主线程意外退出时,子线程可能残留占用资源;
  • 确保连接无论如何都会被关闭,避免套接字资源泄漏;
  • 写入文件时使用绝对路径,防止脚本运行目录变化导致文件找不到,同时添加时间戳便于日志追溯。

修改后的关键代码片段:

def handle_client(self, conn, addr):
    print(f'[{datetime.now().strftime("%H:%M")}][NEW CONNECTION] {addr} connected.')
    s = time.time()
    try:
        while True:
            if time.time() - s > 300:
                print(f'[{datetime.now().strftime("%H:%M")}][CLOSE CONNECTION] {addr} closed (timeout).')
                break
            try:
                msg = conn.recv(2048).decode('utf-8')
            except ConnectionResetError:
                print(f'[{datetime.now().strftime("%H:%M")}][CLOSE CONNECTION] {addr} closed by peers.')
                break
            else:
                if msg:
                    print(f'[{datetime.now().strftime("%H:%M")}] {msg}')
                    # 替换为实际的绝对路径,确保目录已创建
                    with open('/var/tcp_listener/msg.txt','a') as file:
                        file.write(f'[{datetime.now().strftime("%Y-%m-%d %H:%M:%S")}] {msg}\n')
                    s = time.time()
    finally:
        conn.close()
        print(f'[{datetime.now().strftime("%H:%M")}][CONNECTION CLOSED] {addr} socket released.')

# 启动线程时设置为守护线程
thread = threading.Thread(target=self.handle_client, args=(self.conn, addr), daemon=True)

二、使用systemd服务托管脚本(推荐)

Linux下最可靠的持久化运行方式是用systemd将脚本注册为系统服务,实现开机自启、异常自动重启、资源监控:

  1. 创建systemd服务文件/etc/systemd/system/tcp-listener.service:
[Unit]
Description=TCP Listener Service (Port 4995)
After=network.target

[Service]
User=your_username  # 替换为运行脚本的用户(如普通用户或root)
WorkingDirectory=/path/to/script/dir  # 脚本所在目录的绝对路径
ExecStart=/usr/bin/python3 /path/to/script/dir/your_script.py  # 脚本的绝对路径
Restart=always  # 任何情况退出都自动重启
RestartSec=5  # 重启间隔5秒
StandardOutput=append:/var/log/tcp-listener.log  # 标准日志输出文件
StandardError=append:/var/log/tcp-listener.error.log  # 错误日志文件

[Install]
WantedBy=multi-user.target
  1. 配置并启动服务:
# 重新加载systemd配置
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start tcp-listener.service
# 设置开机自启
sudo systemctl enable tcp-listener.service
  1. 常用管理命令:
# 查看服务运行状态
sudo systemctl status tcp-listener.service
# 实时查看服务日志
journalctl -u tcp-listener.service -f
# 手动重启服务
sudo systemctl restart tcp-listener.service

三、其他替代方案

如果暂时不想用systemd,也可以用以下方式托管脚本:

1. 使用screen/tmux保持会话

  • screen:
# 创建新会话
screen -S tcp_listener
# 在会话内运行脚本
python3 your_script.py
# 按Ctrl+A+D分离会话,脚本后台继续运行
# 重新连接会话
screen -r tcp_listener
  • tmux:用法与screen类似,功能更丰富,是screen的现代替代工具。

2. 使用supervisor进程管理

安装supervisor后,创建配置文件/etc/supervisor/conf.d/tcp-listener.conf:

[program:tcp-listener]
command=/usr/bin/python3 /path/to/your_script.py
directory=/path/to/script/dir
user=your_username
autostart=true
autorestart=true
stdout_logfile=/var/log/tcp-listener.log
stderr_logfile=/var/log/tcp-listener.error.log

更新配置并启动:

sudo supervisorctl reread
sudo supervisorctl update
sudo supervisorctl start tcp-listener

内容的提问来源于stack exchange,提问作者Priyansh Khandelwal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:05:24