【问题标题】:Python - Paramiko Client over SSL Socket - Non-Blocking IssuePython - SSL 套接字上的 Paramiko 客户端 - 非阻塞问题
【发布时间】:2021-02-15 15:22:57
【问题描述】:

我编写了一些 Python 代码,使用户能够使用已编辑的 HTML 文件更新我的服务器并上传图像。但是我遇到了一些连接问题。

在服务器端,我在运行 HAproxy 的 pfSense 路由器后面在 VMware 中运行 Ubuntu 虚拟机。代理使具有正确客户端证书的用户能够通过 SSH 连接到正确的机器。现在这已经工作了很长时间了,没有任何问题。

我认为我的问题是在我的 SFTP 代码中,由于 SSL 包装器不是非阻塞的,因此套接字关闭。但是我无法思考或找到修复我的代码的方法。特别是因为我不是使用这些软件包的专家。 Paramiko 客户端和 SFTP 客户端都已在远程服务器上通过 VPN 连接进行了单独测试,它们在这种情况下运行良好。 SSL 套接字使用的证书也可以正常工作。

版本:
Python:3.8.3
openssl:1.1.1.f
帕拉米科:2.7.2

import socket
import ssl
import paramiko

class GE_SFTP_Client:
    def __init__(self, Username, Password):
        self.Username = Username
        self.Password = Password
        
        context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) # Verify Server cert
        context.load_cert_chain(certfile=_client_cert, keyfile=_client_key) # Load Client cert
        context.set_alpn_protocols(['ssh/2.0'])

        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        self.conn = context.wrap_socket(self.s, server_side=False, server_hostname=_target_host)
        self.conn.connect((_proxy_host, _proxy_port))

        self.client = paramiko.SSHClient()
        self.client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

        self.connected_status = False
        SSH_Connection_Tries = 0
        while SSH_Connection_Tries < 4: # Try 4 times to connect.
            try:
                self.client.connect(
                                    hostname=_target_host, username=self.Username, password=self.Password,
                                    sock=self.conn, timeout=200, banner_timeout=200, auth_timeout=200
                                    )
                self.connected_status = True
                break
            except:
                SSH_Connection_Tries += 1
                pass

        if self.connected_status:
            self.sftp = self.client.open_sftp()
    
    def GE_SFTP_ClientEnd(self):
        try:
            self.sftp.close()
        except AttributeError:
            pass
        self.client.close()
        self.conn.close()
        self.s.close()

使用 paramiko SFTP 客户端 get() 一些图像时的输出示例。

succes! /images/fulls/3.jpg
succes! /images/fulls/2.jpg
succes! /images/fulls/9.jpg
Socket exception: A non-blocking socket operation could not be completed immediately (10035)

谢谢您,如果您有任何建议,我们将不胜感激!

【问题讨论】:

  • 您不能多次连接 TCP 套接字,即使连接失败。您必须关闭它并创建一个新的。如果 SSL 包装器是非阻塞的,我会感到惊讶。这是最艰巨的编程任务之一。

标签: python sockets ssl sftp paramiko


【解决方案1】:

我放弃了使用 SSL 包中的标准 SSL 包装器的想法,并找到了一种不同的做事方式,即结合 asyncssh 包和 asyncio。因为它们一起为我提供了解决这个问题所需的工具。

即使在下载较大的文件时,连接现在也更加稳定。我希望这对其他人也有帮助! :)

import socket
import ssl
import asyncio
import asyncssh

class SSL_Socket:
    async def create_connection(self, protocol_factory, host, port):
        loop = asyncio.get_event_loop()

        context = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) # Verify Server cert
        context.load_cert_chain(certfile=_client_cert, keyfile=_client_key) # Load Client cert
        context.set_alpn_protocols(['ssh/2.0'])

        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect((_proxy_host, _proxy_port))
        
        return (await loop.create_connection(protocol_factory, sock=s, ssl=context, server_hostname=host))

async def WorkingExample():
    async with asyncssh.connect(_target_host, tunnel=SSL_Socket(), username=Username, password=Password, known_hosts=_known_hosts) as conn:
        async with conn.start_sftp_client() as sftp:
            print(await sftp.stat(f'{remote_dir}/index.html'))

【讨论】:

    猜你喜欢
    • 2017-04-18
    • 2017-01-29
    • 1970-01-01
    • 2020-02-18
    • 2020-10-30
    • 2012-10-13
    • 2010-12-16
    • 2019-08-23
    • 2016-03-18
    相关资源
    最近更新 更多