使用Twisted在远程系统上运行命令

3 投票
2 回答
1615 浏览
提问于 2025-04-16 23:00

我正在尝试用Twisted写一个客户端/服务器程序,这样客户端就可以在服务器上发出远程命令,并实时接收响应数据。也就是说,如果我运行 $> ssh server someProg.sh,我希望能看到实时的结果,而不是等到整个过程结束后才看到所有结果。请问在Twisted中可以做到这样的功能吗?谢谢。

2 个回答

-1

你可以使用 paramiko 这个库,详细信息可以查看这个链接:http://www.lag.net/paramiko/

import paramiko

class XXX():

def ssh_processing(self, params):

        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy( paramiko.AutoAddPolicy() )

        ssh_connection = ssh.connect(ip, username=params['username'] , password=params['password'])

        result = self.exec_ssh(ssh, cmd)

def exec_ssh(self, ssh, cmd):
    self._log('Exec [%s]' % cmd)
    ( stdin, stdout, stderr ) = ssh.exec_command(cmd)
    data = {
            'stdin'  : '', #self._read_all(stdin),
            'stdout' : self._read_all(stdout), 
            'stderr' : self._read_all(stderr)
        }
    if len(data['stderr']):
        msg = 'SSH Error: [%s]' % data['stderr']
        self._error(msg)

    if 'command not found' in data['stderr']:
        raise Exception(msg)

    return data 
5

当然可以。正如评论中提到的,你可以通过直接用Twisted的“conch”库连接到SSH服务器来实现。这种方法更灵活(你可以打开很多连接而不需要额外的进程),而且更便携(可以在Windows上使用)。不过,它不会考虑你的OpenSSH配置,而且你需要写很多额外的代码来处理像主机密钥验证这样的事情。另一个问题也没有直接回答你主要关心的问题,就是关于如何处理实时输出。

简单来说,答案是“可以”,下面有一个示例程序,它会启动几个子进程,并实时显示它们的输出。你可以把sys.executable替换成其他程序(比如ssh),它的工作方式是一样的。

import os, sys

from twisted.internet.protocol import ProcessProtocol
from twisted.internet import reactor
from twisted.internet.defer import Deferred, gatherResults

script = """
import time
for x in range(3):
    time.sleep(1)
    print(x)
"""

class SimpleProcess(ProcessProtocol):
    def __init__(self, id, d):
        self.id = id
        self.d = d
    def outReceived(self, out):
        print('Received output: {out} from: {proc}'
              .format(out=repr(out), proc=self.id))
    def processEnded(self, reason):
        self.d.callback(None)

ds = []
for x in range(3):
    d = Deferred()
    reactor.callLater(
        x * 0.5, reactor.spawnProcess, SimpleProcess(x, d),
        sys.executable, [sys.executable, '-u', '-c', script],
        os.environ)
    ds.append(d)

gatherResults(ds).addBoth(lambda ignored: reactor.stop())

reactor.run()

撰写回答