关闭 Twisted conch SSH 连接的正确方法是什么?

2024-03-05

关闭 Twisted conch SSH 连接的正确方法是什么?有没有明确的方法来做到这一点?

我见过的所有 Twisted conch 示例都会关闭 SSH 通道,然后停止反应器。反应堆关闭似乎可以处理关闭连接。但是,我将 wxreactor 与 wxPython 一起使用,并且我不想停止反应器,但我想在完成后关闭 ssh 连接。

在查看了 t.c.s.connection 后,似乎 serviceStopped() 方法是正确的选择。它关闭所有打开的通道并在完成后运行 _cleanupGlobalDeferreds() ,但随后我开始收到如下异常:

Unhandled Error
Traceback (most recent call last):
  File "C:\Users\me\venv\lib\site-packages\twisted\internet\tcp.py", line 203, in doRead
    return self._dataReceived(data)
  File "C:\Users\me\venv\lib\site-packages\twisted\internet\tcp.py", line 209, in _dataReceived
    rval = self.protocol.dataReceived(data)
  File "C:\Users\me\venv\lib\site-packages\twisted\conch\ssh\transport.py", line 438, in dataReceived
    self.dispatchMessage(messageNum, packet[1:])
  File "C:\Users\me\venv\lib\site-packages\twisted\conch\ssh\transport.py", line 460, in dispatchMessage
    messageNum, payload)
--- <exception caught here> ---
  File "C:\Users\me\venv\lib\site-packages\twisted\python\log.py", line 84, in callWithLogger
    return callWithContext({"system": lp}, func, *args, **kw)
  File "C:\Users\me\venv\lib\site-packages\twisted\python\log.py", line 69, in callWithContext
    return context.call({ILogContext: newCtx}, func, *args, **kw)
  File "C:\Users\me\venv\lib\site-packages\twisted\python\context.py", line 118, in callWithContext
    return self.currentContext().callWithContext(ctx, func, *args, **kw)
  File "C:\Users\me\venv\lib\site-packages\twisted\python\context.py", line 81, in callWithContext
    return func(*args,**kw)
  File "C:\Users\me\venv\lib\site-packages\twisted\conch\ssh\service.py", line 44, in packetReceived
    return f(packet)
  File "C:\Users\me\venv\lib\site-packages\twisted\conch\ssh\connection.py", line 228, in ssh_CHANNEL_DATA
    channel = self.channels[localChannel]
exceptions.KeyError: 0

看起来通道关闭后我仍在从服务器获取数据。 #twisted 中的某人似乎认为我不应该自己调用 serviceStopped(),因为它应该由 Twisted 的不同部分自动调用。

我在 Twisted 源代码中进行了一些研究,发现 serviceStopped 应该由 t.c.s.t.SSHClientTransport.connectionLost() 调用。

我正在跟踪我的 SFTP 客户端对象并通过其传输属性访问 SSH 连接。这是一个可以在本地运行来演示该问题的示例。可以获取原始数据here https://raw.github.com/Vye/troubleshooting/master/sftp.py.

from os.path import basename
import sys

from twisted.conch.client.connect import connect
from twisted.conch.client.options import ConchOptions
from twisted.internet.defer import Deferred
from twisted.conch.ssh import channel, userauth
from twisted.conch.ssh.common import NS
from twisted.conch.ssh.connection import SSHConnection
from twisted.conch.ssh.filetransfer import FXF_WRITE, FXF_CREAT, \
    FXF_TRUNC, FileTransferClient
from twisted.internet import reactor, defer
from twisted.python.log import startLogging

ACTIVE_CLIENTS = {}
USERNAME = 'user'           # change me!
PASSWORD = 'password'       # change me!
HOST = ('hostname', 22)     # change me!
TEST_FILE_PATH = __file__
TEST_FILE_NAME = basename(__file__)


def openSFTP(user, host):
    conn = SFTPConnection()
    options = ConchOptions()
    options['host'], options['port'] = host
    conn._sftp = Deferred()
    auth = SimpleUserAuth(user, conn)
    connect(options['host'], options['port'], options, verifyHostKey, auth)
    return conn._sftp


def verifyHostKey(ui, hostname, ip, key):
    return defer.succeed(True)


class SimpleUserAuth(userauth.SSHUserAuthClient):
    def getPassword(self):
        return defer.succeed(PASSWORD)


class SFTPConnection(SSHConnection):
    def serviceStarted(self):
        self.openChannel(SFTPChannel())


class SFTPChannel(channel.SSHChannel):
    name = 'session'

    def channelOpen(self, ignoredData):
        d = self.conn.sendRequest(self, 'subsystem', NS('sftp'),
                                  wantReply=True)
        d.addCallback(self._cbFTP)
        d.addErrback(self.printErr)

    def _cbFTP(self, ignore):
        client = FileTransferClient()
        client.makeConnection(self)
        self.dataReceived = client.dataReceived
        ACTIVE_CLIENTS.update({self.conn.transport.transport.addr: client})
        self.conn._sftp.callback(None)

    def printErr(self, msg):
        print msg
        return msg


@defer.inlineCallbacks
def main():
    d = openSFTP(USERNAME, HOST)
    _ = yield d

    client = ACTIVE_CLIENTS[HOST]
    d = client.openFile(TEST_FILE_NAME, FXF_WRITE | FXF_CREAT | FXF_TRUNC, {})
    df = yield d

    sf = open(TEST_FILE_PATH, 'rb')
    d = df.writeChunk(0, sf.read())
    _ = yield d

    sf.close()
    d = df.close()
    _ = yield d

    ACTIVE_CLIENTS[HOST].transport.loseConnection()
    # loseConnection() call above causes the following log messages:
    # [SSHChannel session (0) on SSHService ssh-connection on SSHClientTransport,client] sending close 0
    # [SSHChannel session (0) on SSHService ssh-connection on SSHClientTransport,client] unhandled request for exit-status
    # [SSHChannel session (0) on SSHService ssh-connection on SSHClientTransport,client] remote close
    # [SSHChannel session (0) on SSHService ssh-connection on SSHClientTransport,client] closed
    # I can see the channel closed on the server side:
    # sshd[4485]: debug1: session_exit_message: session 0 channel 0 pid 4486
    # sshd[4485]: debug1: session_exit_message: release channel 0
    # sshd[4485]: debug1: session_by_channel: session 0 channel 0

    ACTIVE_CLIENTS[HOST].transport.conn.transport.loseConnection()
    # loseConnection() call above does not close the SSH connection.

    reactor.callLater(5, reactor.stop)
    # Stopping the reactor closes the SSH connection and logs the following messages:
    # [SSHClientTransport,client] connection lost
    # [SSHClientTransport,client] Stopping factory <twisted.conch.client.direct.SSHClientFactory instance at 0x02E5AF30>
    # [-] Main loop terminated.
    # On the server side:
    # sshd[4485]: Closing connection to xxx.xxx.xxx.xxx


if __name__ == '__main__':
    startLogging(sys.stdout)
    reactor.callWhenRunning(main)
    reactor.run()

要关闭 SSH 连接,我正在调用ACTIVE_CLIENTS[HOST].transport.conn.transport(t.c.c.d.SSHClientTransport instance).loseConnection()哪个调用t.c.c.d.SSHClientTransport.sendDisconnect()。这是 sendDisconnect() 方法:

def sendDisconnect(self, code, reason):
    if self.factory.d is None:
        return
    d, self.factory.d = self.factory.d, None
    transport.SSHClientTransport.sendDisconnect(self, code, reason)
    d.errback(error.ConchError(reason, code))

调用此方法时,self.factory.d 似乎始终为 None,因此它返回而不调用 t.c.s.t.SSHClientTransport.sendDisconnect()。我认为它最初是 t.c.c.d.connect 中的延迟设置,但在某些时候它被设置为 None。

我怀疑 SSHClientTransport.loseConnection() 是关闭 SSH 连接的正确方法,但为什么 self.factory.d 设置为 None 当扭曲期望它是其他东西时?

如果 LoseConnection() 不是关闭 SSH 连接的正确方法,有人可以给我指出正确的方向吗?


听起来你正在使用twisted.conch.client.direct.SSHClientFactory and twisted.conch.client.direct.SSHClientTransport。这些类最直接的目的是用于实现conch命令行工具。这意味着它们对于构建 SSH 客户端相当有用,因为这正是conch is.

然而,它们也不像人们想象的那么普遍有用,因为除了实现conch命令行工具。

更普遍适用的 SSH 客户端传输类别是twisted.conch.ssh.transport.SSHClientTransport。这个类没有任何额外的逻辑来实现某些特定的行为conch命令行工具。它只有 SSH 客户端逻辑。例如,它没有无法解释的self.factory.d检查里面sendDisconnect - its sendDisconnect实现只是发送一个断开连接数据包,然后关闭连接。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

关闭 Twisted conch SSH 连接的正确方法是什么? 的相关文章

随机推荐

  • VBA Excel 中的范围查找

    我正在尝试使用以下指令在 Excel 工作表中执行 查找 Set Found Columns 2 Find What value to find After ActiveCell LookIn xlFormulas LookAt xlPar
  • 有关 IsNullOrWhiteSpace() 的快速提示中的“字符串”与“字符串”

    在 Visual Studio 2015 中工作 我对以下效果进行了条件检查 if String IsNullOrWhiteSpace stringToTest 我看到了一个 IDE001快速提示或行动 https msdn microso
  • 与分布式源代码控制的持续集成

    我想我误解了一些东西 但无法找到到底是什么 我用谷歌搜索 但没有明白这个想法 有两种流行的技术 持续集成和分布式源代码控制 人们以某种 方式将它们结合起来 但我不明白如何结合 AFAIK 持续集成意味着在本地测试代码后立即提交到中央存储库
  • 如何使 WPF 滑块拇指从任意点跟随光标

    我有这样的滑块
  • Google Spreadsheet API 插入图像

    有没有办法通过谷歌电子表格API插入图像 我查看了文档 但除了插入 更新 删除行之外 没有提及与工作表相关的其他数据 例如图像 例如 在 Excel 上 图像附加到工作表而不是任何特定单元格 因此 您必须从工作表中插入删除图像 然后将其放置
  • 如何在 Ubuntu Web 服务器上为 Dart 安装 pub(命令行使用)

    我已按照说明进行操作 在 Linux 选项卡下 将 Dart 安装到 Ubuntu Web 服务器上 Dart 本身工作正常 但我无法使用 Pub 命令 仅限 Dart 命令 如何为服务器安装 Pub 以下是使用 Aptitude apt
  • Google Assistant Dialogflow API V2 webhook ETag 错误

    我正在尝试返回简单的文本响应并使用以下代码在 Google Assistant 应用程序中显示基本卡片 public GoogleCloudDialogflowV2WebhookResponse Search GoogleCloudDial
  • Hadoop 块大小 vs 分割 vs 块大小

    我对 Hadoop 的概念有点困惑 有什么区别Hadoop Chunk size Split size and Block size 提前致谢 块大小和块大小是一样的 分体尺寸可能不同于块 块 size 地图缩减算法不适用于文件的物理块 它
  • 获取当月第一天的最有效方法是什么?

    使用 ruby 我尝试将日期格式化为 2009 10 01 我采用当前日期 2009 10 26 然后将日期更改为 01 我知道有多种方法可以做到这一点 但很好奇从代码角度来看 实现这一目标的最短方法是什么 如果您不介意在应用程序中包含 A
  • 如何使用鼠标滚轮在 WPF 中水平滚动?

    如何使 WPF 能够响应使用鼠标滚轮的水平滚动 例如 我有一个 Microsoft Explorer 迷你鼠标 并尝试使用以下命令水平滚动 ScrollViewer 中包含的内容 HorizontalScrollBarVisibility
  • 使 jQuery 的 .prev().prev().prev().find("selector") 调用更容易

    我怎样才能避免 prev prev prev 打电话 这有捷径吗 您可以使用 prevAll 结合eq or eq since prevAll以相反顺序返回一组元素 从最接近当前元素的元素开始 0 相当于 prev prev prev 将会
  • ODBC 源的版本与此版本的数据流不兼容

    我有一个 SSIS 包 我使用批处理文件通过 DTEXec 运行它 它看起来像这样 cd C Program Files x86 SonicWALL SSL VPN NetExtender NECLI connect s test co u
  • 反序列化复杂对象中的 xml

    我不明白为什么对象为空 WebClient browse new WebClient StreamReader res new StreamReader browse OpenRead http ws audioscrobbler com
  • 将列值与 NA 进行比较

    下面的输入表的数据点是NA 我明白在R当一个值与NA它导致输出是NA 还有办法让我仍然可以使用进行比较ifelse 并确保所比较的值之一是否是NA那么它仍然会提供输出 就像NA是否正在比较字符 字符串 输入原始数据 data lt read
  • 不要在循环内创建函数[重复]

    这个问题在这里已经有答案了 在这种情况下解决 jslint 错误的正确方法是什么 我正在向使用它的对象添加一个 getter 函数 我不知道如何在不创建循环内的函数的情况下执行此操作 for var i 0 i
  • 类在 /Users/... 和 /Applications/... 中实现。使用两者之一。哪一个是未定义的

    我知道这是使用单元测试时的常见错误消息 但我没有这样做 这就是我所做的 我创建了一个新的命令行工具项目 我在print Hello World line 我输入类似的内容po 3 3进入控制台 然后我收到这条消息 objc 929 类 Tt
  • 如何在地图上以最少的重叠绘制网络

    我有一些作者所在的城市或国家 我想知道是否可以在地图上绘制合著者的网络 图 1 其中包含国家的坐标 请考虑来自同一国家 地区的多名作者 编辑 可以像示例中那样生成多个网络 并且不应显示可避免的重叠 这是为数十位作者准备的 缩放选项是可取的
  • \r 不生成换行符

    我使用以下代码 if delanaloge equals stari if novi equals zdruzen else zdruzen zdruzen novi r nap true r附加以创建换行符 但它不会像我预期的那样生成换行
  • VC++中如何判断链接是否存在?

    我有一个链接 我已通过正则表达式检查该链接是否是有效的 URL 现在 我想检查该链接是否是有效的 http 链接 即它不应该是不存在的链接 VC 6 0 MFC 有办法检查吗 一种选择是尝试使用以下方法从该 URL 获取数据URLOpenB
  • 关闭 Twisted conch SSH 连接的正确方法是什么?

    关闭 Twisted conch SSH 连接的正确方法是什么 有没有明确的方法来做到这一点 我见过的所有 Twisted conch 示例都会关闭 SSH 通道 然后停止反应器 反应堆关闭似乎可以处理关闭连接 但是 我将 wxreacto