简体   繁体   English

使用伪 tty 启动多个 ssh 会话时输出乱码(当 ssh 断开连接/被杀死时,需要远程进程退出)

[英]Output garbled when launching multiple ssh-sessions with pseudo-tty (need remote process to exit when ssh disconnects/is killed)

I have a python script that opens multiple concurrent pseudo-tty ssh sessions to a server.我有一个 python 脚本,它打开多个并发的伪 tty ssh 会话到服务器。 My problem is that the output is garbled:我的问题是输出乱码:

for i in range(0, 3):
    subprocess.Popen(
        "ssh -tt -q myserver 'echo 11; echo 22; echo 33; echo 44;'",
        shell=True
    )

Output:输出:

    11
      22
        33
          44
            11
    22
    33
    44
    11
    22
    33
    44

The output varies.输出不同。 Sometimes it works, but most of the time I get those weird indentations.有时它有效,但大多数时候我会得到那些奇怪的缩进。 In reality I want to launch remote python processes (a locust load gen slave), but I've simplified it to just use echo.实际上,我想启动远程 python 进程(locust load gen slave),但我已将其简化为仅使用 echo。

Things I've tried:我尝试过的事情:

  • universal_newlines=True, bufsize=1 (doesnt help) Universal_newlines=True,bufsize=1(没有帮助)
  • remove -tt (fixes the output but has the undesired side effect of remote processes not dying right away if python/ssh is terminated) remove -tt(修复输出,但如果 python/ssh 终止,远程进程不会立即死亡,这会产生不希望的副作用)
  • piping to cat -e to get hidden characters (for debugging):管道到 cat -e 以获取隐藏字符(用于调试):
11^M$
     22^M$
          33^M$
               44^M$
                    11$
22$
33$
44$
11$
   22$
      33$
         44$

I'm not sure if is even a python issue or just an SSH issue.我不确定是 python 问题还是 SSH 问题。 My guess is that I need to use some sort of line buffering, but I dont know how :-/我的猜测是我需要使用某种行缓冲,但我不知道如何:-/

I'm on MacOS Mojave, and I've tried both in iTerm2 and Term if that matters.我在 MacOS Mojave 上,如果重要的话,我已经在 iTerm2 和 Term 中尝试过。

Edit: I'm not sure it is related, but the problem appears to occur more frequently if I ensure python keeps running until the ssh session has terminated (by adding time.sleep(10) at the end of the script)编辑:我不确定它是否相关,但是如果我确保 python 继续运行直到 ssh 会话终止(通过在脚本末尾添加 time.sleep(10) ),问题似乎会更频繁地发生

edit 2: I tried @FLemaitre 's solution (not using -tt and killing explicitly), and it works in the simple case, but not when spawning locust:编辑 2:我尝试了 @FLemaitre 的解决方案(不使用 -tt 并明确杀死),它在简单的情况下有效,但在产卵蝗虫时无效:

proc = subprocess.Popen(
    "ssh servername 'locust --slave --master-port 7777 --no-web -f locustfile.py & read; kill $!'",
    shell=True,
    stdin=subprocess.PIPE,
)
time.sleep(10)
proc.kill()
proc.wait()

On the remote a bash -c locust --slave ... process is started.在远程bash -c locust --slave ...进程启动。 It dies when ssh is killed, but locust itself (a child of the above process) does not :-/它在 ssh 被杀死时死亡,但 locust 本身(上述过程的子进程)不会:-/

I reproduce systematically the issue with the following script:我使用以下脚本系统地重现了该问题:

import subprocess
import time

if __name__ == "__main__":
    for i in range(0, 10):
        proc = subprocess.Popen(
            "ssh -tt -q localhost 'echo 11; echo 22; echo 33; '",
            shell=True
        )
    time.sleep(4)

And I think the issue is not related to Python.而且我认为这个问题与 Python 无关。 These multiple ssh with pseudo-TTY seem to conflict with each other's.这些带有伪 TTY 的多个 ssh 似乎相互冲突。 Eventually, the terminal used to run this script ends up broken as well (whereas it wasn't sourced):最终,用于运行此脚本的终端也被破坏了(而它不是来源):

>cat test2.py
import subprocess
                 import time
                            import atexit
... etc ...

I checked the documentation and this -t option seems to do much more than what you are actually trying to achieve.我检查了文档,这个 -t 选项似乎比你实际想要实现的要多得多。 When I remove the second t and the -q options, I sometimes (not often), get a cryptic error message stating that something went wrong (but I no longer manage to reproduce it).当我删除第二个 t 和 -q 选项时,我有时(不经常)收到一条神秘的错误消息,指出出现问题(但我不再设法重现它)。 I checked with google but without much success.我用谷歌检查过,但没有太大成功。 Still, I'm convinced that this option is overkill and I would rather focus on the undying processes.不过,我相信这个选项是矫枉过正的,我宁愿专注于不朽的过程。 This one issue is well known:这个问题是众所周知的:

Starting a process over ssh using bash and then killing it on sigint 使用 bash 通过 ssh 启动进程,然后在 sigint 上终止它

The second answer is your -tt option, but the best answer suits your example very well and is superior (with -tt you solve the ssh propagation of the termination but do not tackle the same issue between Python and its subprocess).第二个答案是您的 -tt 选项,但最佳答案非常适合您的示例并且更胜一筹(使用 -tt 您可以解决终止的 ssh 传播,但没有解决 Python 及其子进程之间的相同问题)。 For example:例如:

import subprocess
import time

if __name__ == "__main__":
    for i in range(0, 10):
        proc = subprocess.Popen(
            "ssh localhost 'sleep 90 & read ; kill $!'",
            shell=True,
            stdin=subprocess.PIPE
        )
    time.sleep(40)

With this solution, stdin is shared by all actors (python, the python subprocess, the ssh process, the sleep process), and its closure at any point in the chain is detected by the final business process, trigering a graceful shutdown.使用此解决方案,stdin 由所有参与者(python、python 子进程、ssh 进程、sleep 进程)共享,并且它在链中任何点的关闭都被最终业务进程检测到,从而触发正常关闭。

Edit with locust: I gave it a quick try and the issue was that a simple 'kill' is ignored by the slave (looks like an issue on lucust side).用蝗虫编辑:我快速尝试了一下,问题是奴隶忽略了一个简单的“杀戮”(看起来像 lucust 方面的问题)。 It seems to work with a 'kill -9':它似乎适用于“kill -9”:

import subprocess
import time

if __name__ == "__main__":
    for i in range(0, 2):
        proc = subprocess.Popen(
            "ssh localhost 'python -m locust --slave --no-web -f ~devsup/users/flemaitre/tmp/locust_config.py & read ; kill -9 $!'",
            shell=True,
            stdin=subprocess.PIPE
        )
    time.sleep(40)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM