![](/img/trans.png)
[英]SSH shuts down with broken pipe before python program finishes matplotlib part
[英]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
編輯
提議的解決方案:
while os.getppid() != 1
運行腳本 這似乎在Linux系統上工作,但在遠程機器運行OSX時不起作用 。 問題是該命令是在csh中啟動的(見上文),因此csh的父進程id設置為1,而不是腳本。
stderr
這可以,但腳本也在本地運行,我不想打印心跳到stderr
。
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.