簡體   English   中英

當ssh管道壞了時停止python程序

[英]stop python program when ssh pipe is broken

我正在編寫一個帶有無限循環的python腳本,我在ssh上運行。 當某人殺死ssh時,我希望腳本終止。 例如:

腳本(script.py):

while True:
    # do something

將運行為:

ssh foo ./script.py

當我殺死ssh進程時,我希望另一端的腳本停止運行。

我試過尋找一個封閉的標准輸出:

while not sys.stdout.closed:
    # do something

但這沒用。

我該如何實現這一目標?

編輯

遠程機器是Mac,它在csh中打開程序:

502 29352 ??         0:00.01 tcsh -c python test.py
502 29354 ??         0:00.04 python test.py

我正在從python腳本中打開ssh進程,如下所示:

p = Popen(['ssh','foo','./script.py'],stdout=PIPE)

while True:
    line = p.stdout.readline()
    # etc

編輯

提議的解決方案:

  1. 使用while os.getppid() != 1運行腳本

這似乎在Linux系統上工作,但在遠程機器運行OSX時不起作用 問題是該命令是在csh中啟動的(見上文),因此csh的父進程id設置為1,而不是腳本。

  1. 定期登錄stderr

這可以,但腳本也在本地運行,我不想打印心跳到stderr

  1. 使用ssh -tt在pseduo tty中運行腳本。

這確實有效,但有一些奇怪的后果。 考慮以下:

remote_script:

#!/usr/bin/env python
import os
import time
import sys

while True:
    print time.time()
    sys.stdout.flush()
    time.sleep(1)

local_script:

#!/usr/bin/env python
from subprocess import Popen, PIPE
import time

p = Popen(['ssh','-tt','user@foo','remote_script'],stdout=PIPE)

while True:
    line = p.stdout.readline().strip()
    if line:
        print line
    else:
        break
    time.sleep(10)

首先,輸出真的很奇怪,它似乎不斷添加標簽或東西:

[user@local ~]$ local_script 
1393608642.7
            1393608643.71
                         1393608644.71
                                      Connection to foo closed.

其次,程序在第一次收到SIGINT時沒有退出,即我必須按兩次Ctrl-C才能殺死local_script。

好的,我有一個解決方案

當ssh連接關閉時,父進程id將從ssh-deamon的pid(處理連接的fork)更改為1。

因此,以下解決了您的問題。

#!/usr/local/bin/python

from time import sleep
import os

#os.getppid() returns parent pid
while (os.getppid() != 1):
    sleep(1)
    pass

你能否證實這也適合你:)

編輯

我看到你更新了。

這沒有經過測試,但為了讓這個想法適用於OSX,您可能能夠檢測到csh的進程是否發生了變化。 以下代碼僅說明了一個想法,尚未經過測試。 這說我認為它會起作用,但它不會是最優雅的解決方案。 如果可以找到使用signals的跨平台解決方案,那將是優選的。

def do_stuff():
    sleep(1)

if sys.platform == 'darwin':
    tcsh_pid = os.getppid()
    sshfork_pid = psutil.Process(tcsh_pid).ppid
    while (sshfork_pid == psutil.Process(tcsh_pid).ppid)
       do_stuff()

elif sys.platform == 'linux':
    while (os.getppid() != 1):
        sleep(1)
else:
    raise Exception("platform not supported")

sys.exit(1)

你有沒有嘗試過

ssh -tt foo ./script.py

當終端連接丟失時,應用程序應該接收SIGHUP信號 ,所以你要做的就是使用信號模塊注冊一個特殊的處理程序。

import signal
def MyHandler(self, signum, stackFrame):
    errorMessage = "I was stopped by %s" % signum
    raise Exception(errorMessage)

# somewhere in the beginning of the __main__:
# registering the handler
signal.signal(signal.SIGHUP, MyHandler)

請注意,您很可能必須處理其他一些信號。 你可以用完全相同的方式做到這一點。

我建議定期登錄到stderr。

當您不再有要寫入的stderr時,這將導致發生異常。

正在運行的腳本是終端會話的子pid。 如果正確關閉SSH會話,它將終止該過程。 但是,另一種解決方法是將while循環連接到另一個因素並將其與SSH會話斷開連接。

您可以讓cron控制腳本定期執行。 你可以讓while循環有一個計數器。 您可以在循環中使用sleep命令來控制執行。 除了將其連接到SSH會話之外的任何其他內容都是有效的。

為此,您可以使用exec&從循環中斷開實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM