Question

Placez les éléments suivants dans un fichier hello.py (et easy_install paramiko si vous ne l'avez pas encore obtenu):

hostname,username,password='fill','these','in'
import paramiko
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=hostname, username=username, password=password)
i,o,e = c.exec_command('ls /')
print(o.read())
c.close()

Remplissez la première ligne de manière appropriée.

Maintenant tapez

python hello.py

et vous verrez une sortie ls.

À la place, tapez

python

puis à partir du type d'interprète

import hello

et le tour est joué! Ça pend! Cela se dissipera si vous enveloppez le code dans une fonction foo et que vous faites import hello; hello.foo () à la place.

Pourquoi Paramiko se bloque-t-il lorsqu'il est utilisé dans l'initialisation du module? Comment Paramiko sait-il qu'il est utilisé lors de l'initialisation du module?

Était-ce utile?

La solution

Paramiko utilise des threads distincts pour le transport sous-jacent. Vous devriez jamais avoir un module qui génère un thread en tant qu'effet secondaire de l'importation. Si j'ai bien compris, un seul verrou d'importation est disponible. Ainsi, lorsqu'un thread enfant de votre module tente une autre importation, il peut se bloquer indéfiniment, car votre thread principal détient toujours le verrou. (Il y a probablement d'autres pièges que je ne connais pas trop)

En règle générale, les modules ne devraient pas avoir d’effets secondaires lors de l’importation, sinon vous obtiendrez des résultats imprévisibles. Attendez simplement l'exécution avec le truc __ name__ == '__main __' , et tout ira bien pour vous.

[EDIT] Je n'arrive pas à créer un cas de test simple reproduisant cette impasse. Je suppose toujours que c'est un problème de thread avec l'importation, car le code d'autorisation attend un événement qui ne se déclenche jamais. Cela peut être un bug dans paramiko, ou python, mais la bonne nouvelle est que vous ne devriez jamais le voir si vous faites les choses correctement;)

C’est un bon exemple de la raison pour laquelle vous souhaitez toujours minimiser les effets secondaires et des techniques de programmation fonctionnelle qui se répandent de plus en plus.

Autres conseils

Comme JimB a souligné qu'il s'agit d'un problème d'importation lorsque python tente d'importer implicitement le Décodeur str.decode ('utf-8') lors de la première utilisation lors d'une tentative de connexion ssh. Voir la section Analyse pour plus de détails.

En général, on ne saurait trop insister pour que vous évitiez qu'un module ne génère automatiquement de nouveaux threads lors de l'importation. Si vous le pouvez, essayez d’éviter le code de module magique en général car il entraîne presque toujours des effets secondaires indésirables.

  1. Comme cela a déjà été mentionné, la solution simple à votre problème consiste à placer votre code dans un si __name__ == '__main __': qui ne sera exécuté que si vous exécutez ce module spécifique et ne sera pas exécuté lorsque ce module est importé par d'autres modules.

  2. (non recommandé) Une autre solution consiste à créer un code factice str.decode ('utf-8') dans votre code avant d'appeler SSHClient.connect () - voir l'analyse ci-dessous. .

Alors, quelle est la cause première de ce problème?

Analyse (authentification par mot de passe simple)

Conseil: si vous souhaitez déboguer un thread dans une importation Python et définir threading._VERBOSE = True

  1. paramiko.SSHClient (). connect (.., look_for_keys = False, ..) génère implicitement un nouveau thread pour votre connexion. Vous pouvez également le voir si vous activez la sortie de débogage pour paramiko.transport .

[Thread-5] [paramiko.transport] DEBUG: thread de démarrage (mode client): 0x317f1d0L

  1. Ceci est essentiellement fait dans le cadre de SSHClient.connect () . Lorsque client.py:324::start_client () est appelé, un verrou est créé transport.py:399::event=threading.Event () et le fil est a commencé transport.py:400::self.start () . Notez que la méthode start () exécutera ensuite la méthode transport.py:1565::run () de la classe.

  2. transport.py:1580::self._log (..) imprime le message de notre journal, "fil de départ". puis passe à transport.py:1584::self._check_banner () .

  3. check_banner fait une chose. Il récupère la bannière ssh (première réponse du serveur) transport.py:1707::self.packetizer.readline (délai d'attente) (notez que le délai d'attente est simplement un délai d'attente de lecture de socket), recherche un saut de ligne à la fin et sinon expire.

  4. Au cas où une bannière de serveur serait reçue, elle essaiera de décoder la chaîne de réponse packet.py:287::return u (buf) et l’endroit dans lequel l’interblocage se produit. Le u (s, encoding = 'utf-8') effectue un str.decode ('utf-i') et importe implicitement encodings.utf8 dans les encodages . : 99 via encodings.search_function aboutissant dans une impasse d'importation.

Donc, un correctif serait de simplement importer une fois le décodeur utf-8 afin de ne pas bloquer cette importation spécifique en raison d'effets secondaires d'importation de module. ( ''. decode ('utf-8') )

Correction

correctif sale - non recommandé

import paramiko
hostname,username,password='fill','these','in'
''.decode('utf-8')  # dirty fix
c = paramiko.SSHClient()
c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
c.connect(hostname=hostname, username=username, password=password)
i,o,e = c.exec_command('ls /')
print(o.read())
c.close()

bonne solution

import paramiko
if __name__ == '__main__':
    hostname,username,password='fill','these','in'
    c = paramiko.SSHClient()
    c.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    c.connect(hostname=hostname, username=username, password=password)
    i,o,e = c.exec_command('ls /')
    print(o.read())
    c.close()

réf. suivi des problèmes de paramiko: numéro 104

".decode (" utf-8 ") n'a pas fonctionné pour moi, j'ai fini par le faire.

from paramiko import py3compat
# dirty hack to fix threading import lock (issue 104) by preloading module
py3compat.u("dirty hack")

J'ai un wrapper pour paramiko avec cette implémentation. https://github.com/bucknerns/sshaolin

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top