您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

扭曲的海螺文件传输

扭曲的海螺文件传输

使用Twisted Conch进行SFTP文件传输涉及两个不同的阶段(嗯,如果斜视,它们是不同的)。基本上,首先,您需要建立一个连接,并在其上打开一个通道,并在其上运行sftp子系统。ew。然后,您可以使用连接到该通道的FileTransferClient实例的方法来执行您要执行的SFTP操作。

Twisted.conch.client软件包中的模块提供的API可以帮助您建立SSH连接。这是一个twisted.conch.client.default.connect一个不太令人惊讶的界面中包裹了一点怪异功能函数

from twisted.internet.defer import Deferred
from twisted.conch.scripts.cftp import ClientOptions
from twisted.conch.client.connect import connect
from twisted.conch.client.default import SSHUserAuthClient, verifyHostKey

def sftp(user, host, port):
    options = ClientOptions()
    options['host'] = host
    options['port'] = port
    conn = SFTPConnection()
    conn._sftp = Deferred()  
    auth = SSHUserAuthClient(user, options, conn)
    connect(host, port, options, verifyHostKey, auth)
    return conn._sftp

功能采用用户名,主机名(或IP地址)和端口号,并使用与给定用户名关联的帐户在该地址建立到服务器的身份验证SSH连接。

实际上,它的作用还不止于此,因为此处的SFTP设置有点混杂。但是暂时,请忽略SFTPConnection,然后再_sftp递延。

ClientOptions基本上只是一本花哨的字典,connect希望能够看到它所连接的内容,以便可以验证主机密钥。

SSHUserAuthClient是定义身份验证如何进行的对象。此类知道如何尝试常见的事情,例如查看~/.ssh本地SSH代理并与之交谈。如果要更改身份验证的方式,则可以使用该对象。你也可以继承SSHUserAuthClient并覆盖其getpasswordgetPublicKeygetPrivateKey,和/或signData方法,或者你可以写有你想要的任何其他身份验证逻辑自己完全不同的类。查看实现,以查看SSH协议实现调用哪种方法来完成身份验证。

因此,此功能将建立SSH连接并进行身份验证。完成之后,SFTPConnection实例开始起作用。注意如何SSHUserAuthClientSFTPConnection实例作为参数。身份验证成功后,它将移交对该实例连接的控制。特别是,该实例已对其进行了serviceStarted调用。这是SFTPConnection该类的完整实现:

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

很简单:要做的就是打开一个新频道。SFTPSession它传入的实例将与该新通道进行交互。这是我的定义方式SFTPSession

class SFTPSession(SSHChannel):
    name = 'session'

    def channelOpen(self, whatever):
        d = self.conn.sendRequest(
            self, 'subsystem', NS('sftp'), wantReply=True)
        d.addCallbacks(self._cbSFTP)


    def _cbSFTP(self, result):
        client = FileTransferClient()
        client.makeConnection(self)
        self.dataReceived = client.dataReceived
        self.conn._sftp.callback(client)

与相似SFTPConnection,此类具有一个在连接准备就绪时被调用方法在这种情况下,当成功打开通道时调用它,方法channelOpen

最后,启动SFTP子系统的要求已经到位。因此,channelOpen通过通道发送请求以启动该子系统。它要求答复,以便可以知道何时成功(或失败)。它增加一个回调到Deferred它会挂钩一个FileTransferClient给自己。

FileTransferClient实例将实际格式化和解析在连接的此通道上移动的字节。换句话说,它 SFTP协议的一种实现。它运行在SSH协议上,此示例创建的其他对象都在使用该协议。但是就其而言,它在其dataReceived方法中接收字节,对其进行解析并将数据分派给回调,并且它提供了一些方法,这些方法接受结构化的Python对象,将这些对象格式化为正确的字节,并将其写入其传输中。

不过,这些都不是直接使用它的重要意义。但是,在给出如何使用它执行SFTP操作的示例之前,让我们介绍一下该_sftp属性。这是我使该新连接的FileTransferClient实例可用于其他一些实际上知道如何处理它的代码的粗略方法。将SFTP设置代码与实际使用SFTP连接的代码分开,可以更轻松地重用前者,同时更改后者。

因此,Deferred我设置为insftpFileTransferClient连接被解雇了_cbSFTP。然后sftpget的调用Deferred返回给他们,以便代码可以执行以下操作:

def transfer(client):
    d = client.makeDirectory('foobarbaz', {})
    def cbDir(ignored):
        print 'Made directory'
    d.addCallback(cbDir)   
    return d


def main():
    ...
    d = sftp(user, host, port)
    d.addCallback(transfer)

因此,首先要sftp建立整个连接,一路将本地FileTransferClient实例连接到字节流,该字节流的另一端具有一些SSH服务器的SFTP子系统,然后transfer使用该实例并使用它来创建目录,的方法FileTransferClient进行一些SFTP操作。

这是一个完整的代码列表,您应该可以运行该代码,并查看在某些SFTP服务器上创建的目录:

from sys import stdout

from twisted.python.log import startLogging, err

from twisted.internet import reactor
from twisted.internet.defer import Deferred

from twisted.conch.ssh.common import NS
from twisted.conch.scripts.cftp import ClientOptions
from twisted.conch.ssh.filetransfer import FileTransferClient
from twisted.conch.client.connect import connect
from twisted.conch.client.default import SSHUserAuthClient, verifyHostKey
from twisted.conch.ssh.connection import SSHConnection
from twisted.conch.ssh.channel import SSHChannel


class SFTPSession(SSHChannel):
    name = 'session'

    def channelOpen(self, whatever):
        d = self.conn.sendRequest(
            self, 'subsystem', NS('sftp'), wantReply=True)
        d.addCallbacks(self._cbSFTP)


    def _cbSFTP(self, result):
        client = FileTransferClient()
        client.makeConnection(self)
        self.dataReceived = client.dataReceived
        self.conn._sftp.callback(client)



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


def sftp(user, host, port):
    options = ClientOptions()
    options['host'] = host
    options['port'] = port
    conn = SFTPConnection()
    conn._sftp = Deferred()
    auth = SSHUserAuthClient(user, options, conn)
    connect(host, port, options, verifyHostKey, auth)
    return conn._sftp


def transfer(client):
    d = client.makeDirectory('foobarbaz', {})
    def cbDir(ignored):
        print 'Made directory'
    d.addCallback(cbDir)
    return d


def main():
    startLogging(stdout)

    user = 'exarkun'
    host = 'localhost'
    port = 22
    d = sftp(user, host, port)
    d.addCallback(transfer)
    d.addErrback(err, "Problem with SFTP transfer")
    d.addCallback(lambda ignored: reactor.stop())
    reactor.run()


if __name__ == '__main__':
    main()

makeDirectory一个相当简单的操作。该makeDirectory方法返回一个Deferred在创建目录时触发(或在执行此操作时发生错误)时触发的。传输文件要复杂得多,因为您必须提供要发送的数据,或者定义在下载而不是上传时如何解释接收到的数据。

但是,如果您阅读docstring的方法FileTransferClient,则应该了解如何使用其其他功能- 对于实际文件传输,openFile主要是感兴趣的。它为您Deferred提供了一个使用ISFTPFile提供程序触发的功能。该对象具有读取和写入文件内容方法

其他 2022/1/1 18:31:22 有457人围观

撰写回答


你尚未登录,登录后可以

和开发者交流问题的细节

关注并接收问题和回答的更新提醒

参与内容的编辑和改进,让解决方法与时俱进

请先登录

推荐问题


联系我
置顶