복붙노트

[PYTHON] 트위스트 conch 파일 전송

PYTHON

트위스트 conch 파일 전송

나는 파이썬에서 트위스트 conch를 사용하여 매우 간단한 파일 전송 클라이언트를 구현하려고합니다. 클라이언트는 프로그램 적으로 원격 ssh / sftp 서버에 몇 개의 파일을 전송해야합니다. 이 함수는 username, password, file list, destination server : 디렉토리를 제공받으며 인증과 복사를 크로스 플랫폼 방식으로 수행해야합니다.

나는 트위스트 된 입문 자료를 읽고 원격 서버에서 cat을 실행하는 내 SSH 클라이언트를 만들었습니다. 나는 이것을 파일을 옮기는 것에까지 확장하는 데 정말로 어려움을 겪고있다. 나는 cftp.py와 filetransfer 테스트를 살펴 보았지만, 뒤틀린 것으로 완전히 신비하게 여긴다.

누구든지 올바른 방향으로 나를 가리킬 수있는 제안이나 참조가 있습니까? 이미 구축 한 SSH 클라이언트는이 기반을 기반으로합니다.

해결법

  1. ==============================

    1.Twisted Conch로 SFTP 파일 전송을하는 것은 몇 가지 단계를 포함합니다. 기본적으로 먼저 sftp 서브 시스템이 실행되는 채널을 열고 연결을 설정해야합니다. 아휴. 그런 다음 해당 채널에 연결된 FileTransferClient 인스턴스의 메서드를 사용하여 수행하려는 SFTP 작업을 수행 할 수 있습니다.

    Twisted Conch로 SFTP 파일 전송을하는 것은 몇 가지 단계를 포함합니다. 기본적으로 먼저 sftp 서브 시스템이 실행되는 채널을 열고 연결을 설정해야합니다. 아휴. 그런 다음 해당 채널에 연결된 FileTransferClient 인스턴스의 메서드를 사용하여 수행하려는 SFTP 작업을 수행 할 수 있습니다.

    SSH 연결을 설정하는 데 필요한 기본 사항은 twisted.conch.client 패키지의 모듈에서 제공하는 API로 처리 할 수 ​​있습니다. 약간 덜 놀라운 인터페이스에서 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 Deferred를 무시하십시오.

    ClientOptions는 기본적으로 connect가 연결 대상을 볼 수 있기를 원하기 때문에 호스트 키를 확인할 수있는 멋진 사전입니다.

    SSHUserAuthClient는 인증이 일어날 방법을 정의하는 객체입니다. 이 클래스는 ~ / .ssh를보고 로컬 SSH 에이전트와 대화하는 것과 같은 일반적인 작업을 수행하는 방법을 알고 있습니다. 인증이 수행되는 방식을 변경하려면이 객체를 가지고 놀아야합니다. SSHUserAuthClient를 서브 클래스 화하고 getPassword, getPublicKey, getPrivateKey 및 / 또는 signData 메소드를 겹쳐 쓰거나, 원하는 다른 인증 로직을 가진 완전히 다른 클래스를 작성할 수 있습니다. SSH 프로토콜 구현이 인증을 수행하기 위해 호출하는 메소드를 확인하려면 구현을 살펴보십시오.

    따라서이 기능은 SSH 연결을 설정하고 인증합니다. 완료되면 SFTPConnection 인스턴스가 작동합니다. SSHUserAuthClient가 SFTPConnection 인스턴스를 인수로 취하는 방법에 주목하십시오. 인증이 성공하면 해당 인스턴스에 대한 연결 제어가 해제됩니다. 특히, 해당 인스턴스에서 호출 된 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 설치 코드를 분리하면 후자를 변경하면서 SFTP 설치 코드를 쉽게 재사용 할 수 있습니다.

    그래서 sftp에 설정된 Deferred I는 _cbSFTP에 연결된 FileTransferClient로 해고 당합니다. 그리고 SFTP를 호출 한 사람은 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 하위 시스템이있는 바이트 스트림까지 연결 한 다음 전송하여 해당 인스턴스를 가져와 다음과 같이 SFTP 작업을 수행하기위한 FileTransferClient의 메소드 중 하나.

    다음은 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 메소드는 디렉토리가 생성 될 때 (또는 에러가 발생하는 경우) 발생하는 지연을 반환합니다. 전송할 데이터를 제공해야하거나 업로드하는 대신 다운로드하는 경우 수신 된 데이터가 해석되는 방식을 정의해야하기 때문에 파일 전송은 좀 더 복잡합니다.

    그러나 FileTransferClient의 메소드에 대한 docstring을 읽는다면 다른 기능을 사용하는 방법을 볼 수 있습니다. 실제 파일 전송의 경우 openFile이 주로 중요합니다. 그것은 당신에게 ISFTPFile 프로 바이더와 함께 발생하는 지연을 제공합니다. 이 객체에는 파일 내용을 읽고 쓰는 메서드가 있습니다.

  2. ==============================

    2.SSH 클라이언트는 다른 OS 서비스와 독립적 인 것이 아닙니다. .ssh 폴더, 키 체인 등의 지원을 정말로 추가 하시겠습니까? Windows에서 scp (Linux, OSX) 및 pscp 주위에 래퍼를 만드는 것이 더 빠르고 강력 할 수 있습니다. 그리고이 방법은 더 많은 "Linux 방식"을 보여줍니다 (기존의 작은 조각을 복잡한 것으로 연결).

    SSH 클라이언트는 다른 OS 서비스와 독립적 인 것이 아닙니다. .ssh 폴더, 키 체인 등의 지원을 정말로 추가 하시겠습니까? Windows에서 scp (Linux, OSX) 및 pscp 주위에 래퍼를 만드는 것이 더 빠르고 강력 할 수 있습니다. 그리고이 방법은 더 많은 "Linux 방식"을 보여줍니다 (기존의 작은 조각을 복잡한 것으로 연결).

  3. from https://stackoverflow.com/questions/5195427/twisted-conch-filetransfer by cc-by-sa and MIT license