:Python 中处理信号会导致 FTP 连接中断

57 阅读2分钟

此脚本检查 FTP 并按计划间隔下载文件。向它发送正确的信号 (SIGUSR1) 应该让它优雅地关闭,等待 checkAll 完成(如果正在运行)。当通过信号尝试关闭程序时,FTP 连接意外中断,同时在尝试从 FTP 下载文件时引发 [Errno 4] Interrupted system call 错误。

  1. 解决方案

为了防止 FTP 连接中断,可以采用以下解决方案:

  1. 自定义信号处理程序
import signal
import ftplib

class FtpClient:
    def __init__(self):
        self.ftp = ftplib.FTP()
        self.is_connected = False

    def connect(self, host, username, password):
        self.ftp.connect(host, username, password)
        self.is_connected = True

    def download(self, remote_file, local_file):
        with open(local_file, "wb") as f:
            self.ftp.retrbinary("RETR " + remote_file, f.write)

    def quit(self):
        if self.is_connected:
            self.ftp.quit()
            self.is_connected = False

# 自定义信号处理程序
def signal_handler(signum, frame):
    print("Received signal:", signum)
    client.quit()  # 关闭 FTP 连接

# 注册信号处理程序
signal.signal(signal.SIGINT, signal_handler)

if __name__ == "__main__":
    host = "your_ftp_host"
    username = "your_username"
    password = "your_password"
    remote_file = "your_remote_file"
    local_file = "your_local_file"

    client = FtpClient()
    client.connect(host, username, password)
    client.download(remote_file, local_file)

    # 等待一段时间,以便有机会发送信号
    time.sleep(10)

    # 发送中断信号
    os.kill(os.getpid(), signal.SIGINT)

以上代码自定义了一个信号处理程序 signal_handler 来处理 SIGINT 信号,当接收到该信号时,它会关闭 FTP 连接。注册信号处理程序后,脚本下载文件后等待一段时间,然后发送中断信号 (SIGINT)。这样,即使在下载过程中接收到中断信号,也不会中断 FTP 连接。

  1. 使用 try...except 结构捕获异常
import signal
import ftplib

class FtpClient:
    def __init__(self):
        self.ftp = ftplib.FTP()
        self.is_connected = False

    def connect(self, host, username, password):
        self.ftp.connect(host, username, password)
        self.is_connected = True

    def download(self, remote_file, local_file):
        try:
            with open(local_file, "wb") as f:
                self.ftp.retrbinary("RETR " + remote_file, f.write)
        except ftplib.error_temp as e:
            print("Temporary error:", e)
            # 重新尝试下载
            self.download(remote_file, local_file)
        except ftplib.error_perm as e:
            print("Permanent error:", e)

    def quit(self):
        if self.is_connected:
            self.ftp.quit()
            self.is_connected = False

# 自定义信号处理程序
def signal_handler(signum, frame):
    print("Received signal:", signum)
    client.quit()  # 关闭 FTP 连接

# 注册信号处理程序
signal.signal(signal.SIGINT, signal_handler)

if __name__ == "__main__":
    host = "your_ftp_host"
    username = "your_username"
    password = "your_password"
    remote_file = "your_remote_file"
    local_file = "your_local_file"

    client = FtpClient()
    client.connect(host, username, password)
    client.download(remote_file, local_file)

    # 等待一段时间,以便有机会发送信号
    time.sleep(10)

    # 发送中断信号
    os.kill(os.getpid(), signal.SIGINT)

以上代码使用 try...except 结构来捕获 ftplib.error_tempftplib.error_perm 异常,以便在下载过程中发生临时错误时重新尝试下载。这样,即使在下载过程中接收到中断信号,也不会中断 FTP 连接,并且会尝试重新下载文件。