복붙노트

[PYTHON] 큰 출력을 읽을 때 Paramiko 채널이 멈 춥니 다.

PYTHON

큰 출력을 읽을 때 Paramiko 채널이 멈 춥니 다.

필자는 원격 Linux 컴퓨터에서 명령을 실행하고 Paramiko를 사용하여 출력을 읽는 코드를 가지고 있습니다. 코드 def는 다음과 같습니다.

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(IPAddress, username=user['username'], password=user['password'])


chan = self.ssh.get_transport().open_session()

chan.settimeout(10800)

try:
    # Execute thecommand
    chan.exec_command(cmd)

    contents = StringIO.StringIO()

    data = chan.recv(1024)

    # Capturing data from chan buffer.
    while data:
        contents.write(data)
        data = chan.recv(1024)

except socket.timeout:
    raise socket.timeout


output = contents.getvalue()

return output,chan.recv_stderr(600),chan.recv_exit_status()

위의 코드는 작은 출력에서는 작동하지만 큰 출력에서는 문제가됩니다.

여기에 버퍼 관련 문제가 있습니까?

해결법

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

    1.stdout 채널과 관련된 문제는 보이지 않지만 stderr을 처리하는 방법에 대해서는 확실하지 않습니다. 문제를 일으키는 표준 오류를 포착 한 것이 아니라 확인할 수 있습니까? 코드를 시험해보고 알려 드리겠습니다.

    stdout 채널과 관련된 문제는 보이지 않지만 stderr을 처리하는 방법에 대해서는 확실하지 않습니다. 문제를 일으키는 표준 오류를 포착 한 것이 아니라 확인할 수 있습니까? 코드를 시험해보고 알려 드리겠습니다.

    최신 정보: STDERR에서 실행하는 명령이 많은 메시지를 제공하면 코드가 멈 춥니 다. 왜 그런지는 모르지만 recv_stderr (600)이 이유 일 수 있습니다. 따라서 표준 출력을 캡처하는 것과 같은 방식으로 오류 스트림을 캡처하십시오. 어떤 것,

    contents_err = StringIO.StringIO()
    
    data_err = chan.recv_stderr(1024)
    while data_err:
        contents_err.write(data_err)
        data_err = chan.recv_stderr(1024)
    

    recv_stderr (600) 이상을 recv_stderr (1024) 이상으로 변경해보십시오.

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

    2.나는 브루스 웨인 (:)으로부터 입력으로 작업 한 최종 코드를 게시하고 있습니다.

    나는 브루스 웨인 (:)으로부터 입력으로 작업 한 최종 코드를 게시하고 있습니다.

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(IPAddress, username=user['username'], password=user['password'])
    
    chan = self.ssh.get_transport().open_session()
    chan.settimeout(10800)
    
    try:
        # Execute the given command
        chan.exec_command(cmd)
    
        # To capture Data. Need to read the entire buffer to capture output
        contents = StringIO.StringIO()
        error = StringIO.StringIO()
    
        while not chan.exit_status_ready():
            if chan.recv_ready():
                data = chan.recv(1024)
                #print "Indside stdout"
                while data:
                    contents.write(data)
                    data = chan.recv(1024)
    
            if chan.recv_stderr_ready():            
                error_buff = chan.recv_stderr(1024)
                while error_buff:
                    error.write(error_buff)
                    error_buff = chan.recv_stderr(1024)
    
        exit_status = chan.recv_exit_status()
    
    except socket.timeout:
        raise socket.timeout
    
    output = contents.getvalue()
    error_value = error.getvalue()
    
    return output, error_value, exit_status
    
  3. ==============================

    3.사실 위의 모든 대답이 실제 문제를 해결할 수 없다고 생각합니다.

    사실 위의 모든 대답이 실제 문제를 해결할 수 없다고 생각합니다.

    원격 프로그램이 stderr 출력을 대량으로 생성한다면

    stdout.readlines()
    stderr.readlines()
    

    영원히 걸릴 것입니다. 이기는 하지만

    stderr.readlines()
    stdout.readlines()
    

    이 경우는 해결되지만 원격 프로그램이 대량의 stdout 출력을 먼저 생성하는 경우 실패합니다.

    아직 해결책이 없습니다 ...

  4. ==============================

    4.열린 ssh 세션의 상위 레벨 표현을 사용하면 더 쉽습니다. 이미 ssh-client를 사용하여 채널을 열었으므로 그곳에서 명령을 실행하고 추가 작업을 피할 수 있습니다.

    열린 ssh 세션의 상위 레벨 표현을 사용하면 더 쉽습니다. 이미 ssh-client를 사용하여 채널을 열었으므로 그곳에서 명령을 실행하고 추가 작업을 피할 수 있습니다.

    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(IPAddress, username=user['username'], password=user['password'])
    
    stdin, stdout, stderr = ssh.exec_command(cmd)
    for line in stdout.readlines():
        print line
    for line in stderr.readlines():
        print line
    

    이후에 추가 데이터를 받으면 다시 돌아와서이 파일에서 읽어야합니다.

  5. ==============================

    5.paramiko 명령을 subprocess.call처럼 동작 시키려면 다음 코드를 사용할 수 있습니다 (python-3.5 및 paramiko-2.1.1에서 테스트 됨).

    paramiko 명령을 subprocess.call처럼 동작 시키려면 다음 코드를 사용할 수 있습니다 (python-3.5 및 paramiko-2.1.1에서 테스트 됨).

    #!/usr/bin/env /usr/bin/python3                                                
    
    import os                                                                  
    import sys                                                                                                                    
    from paramiko import SSHClient, AutoAddPolicy               
    from socket import getfqdn                                       
    
    class SecureSHell(object):                                                 
        reuser = os.environ['USER']                                            
        remote = ''                                                            
        def __init__(self, *args, **kwargs):                                   
            for arg in args:                                                   
                if hasattr(self, arg):                                         
                    setattr(self, arg, True)                                   
            for (key, val) in kwargs.items():                                  
                if hasattr(self, key):                                         
                    setattr(self, key, val)
    
        @staticmethod                                                          
        def _ssh_(remote, reuser, port=22):                                    
            if '@' in remote:                                                  
                _reuser, remote = remote.split('@')                            
            _fqdn = getfqdn(remote)                                            
            remote = _fqdn if _fqdn else remote                                
            ssh = SSHClient()                                                  
            ssh.set_missing_host_key_policy(AutoAddPolicy()) 
            ssh.connect(remote, int(port), username=reuser)                                                                     
            return ssh                                                         
    
        def call(self, cmd, remote=None, reuser=None):                         
            remote = remote if remote else self.remote                         
            reuser = reuser if reuser else self.reuser              
            ssh = self._ssh_(remote, reuser)                                   
            chn = ssh.get_transport().open_session()                           
            chn.settimeout(10800)                                              
            chn.exec_command(cmd)                                              
            while not chn.exit_status_ready():                                 
                if chn.recv_ready():                                           
                    och = chn.recv(1024)                                       
                    while och:                                                 
                        sys.stdout.write(och.decode())                         
                        och = chn.recv(1024)                                   
                if chn.recv_stderr_ready():                                    
                    ech = chn.recv_stderr(1024)                                
                    while ech:                                                 
                        sys.stderr.write(och.decode())                         
                        ech = chn.recv_stderr(1024)                            
            return int(chn.recv_exit_status())                                 
    
    ssh = SecureSHell(remote='example.com', user='d0n')                       
    ssh.call('find')                                                           
    
  6. from https://stackoverflow.com/questions/14643861/paramiko-channel-stucks-when-reading-large-ouput by cc-by-sa and MIT license