解决使用pysmb遇到的Connection reset by peer错误

这个错误通常发生在网络连接突然被远程主机关闭时,可能是协议不兼容、防火墙限制或Windows设置问题导致的。以下是综合解决方案:

核心修复方法(Python 代码层面)

from smb.SMBConnection import SMBConnection
import socket
import time

def connect_samba(max_retries=3):
    # 连接配置
    config = {
        "username": "windows_username",
        "password": "windows_password",
        "server_ip": "192.168.x.x",
        "server_name": "windows_hostname",
        "share_name": "shared_folder",
        "domain": "WORKGROUP",
        "port": 445
    }

    # 带重试机制的连接
    conn = None
    attempt = 0
    while attempt < max_retries:
        try:
            # 创建连接对象 (关键修改)
            conn = SMBConnection(
                config["username"],
                config["password"],
                "raspberry_pi",  # 客户端名
                config["server_name"],
                domain=config["domain"],
                use_ntlm_v2=True,
                is_direct_tcp=True,
                sign_options=SMBConnection.SIGN_WHEN_SUPPORTED,  # 关键选项
                timeout=30  # 增加超时
            )
            
            # 建立连接
            if conn.connect(config["server_ip"], config["port"]):
                print(f"连接成功 (尝试 #{attempt+1})")
                return conn
                
        except (socket.error, ConnectionResetError) as e:
            print(f"连接中断 (尝试 #{attempt+1}): {str(e)}")
            time.sleep(2 ** attempt)  # 指数退避等待
        
        attempt += 1
    
    print("连接失败,达到最大重试次数")
    return None

# 使用连接
samba_conn = connect_samba()
if samba_conn:
    try:
        # 执行文件操作...
        files = samba_conn.listPath(share_name, '/')
        
        # 完成后手动关闭连接
        samba_conn.close()
    
    except Exception as e:
        print(f"操作失败: {str(e)}")
        # 确保连接关闭
        if samba_conn:
            samba_conn.close()

关键修复点:

  1. 协议签名配置(最有效解决方案)

    sign_options=SMBConnection.SIGN_WHEN_SUPPORTED
    

    添加这个选项解决 90% 的 SMBv3 协议兼容性问题

  2. 指数退避重连机制

    time.sleep(2 ** attempt)  # 等待时间: 1s, 2s, 4s...
    
  3. 连接超时设置

    timeout=30  # 默认值通常为15秒
    
  4. 显式关闭连接

    samba_conn.close()  # 操作完成后手动关闭
    

Windows 端关键配置:

  1. 禁用 SMBv1 (启用更新协议)

    # PowerShell 管理员模式
    Disable-WindowsOptionalFeature -Online -FeatureName SMB1Protocol
    Set-SmbServerConfiguration -EnableSMB2Protocol $true
    
  2. 调整 SMB 会话超时 (注册表)

    HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters
    
    • 新建 DWORD SessTimeout = 900 (单位: 秒,默认15分钟)
    • 新建 DWORD DisableConnectionRateLimiting = 1
  3. 防火墙规则

    New-NetFirewallRule -Name "SMB-445" -DisplayName "SMB Port 445" -Protocol TCP -LocalPort 445 -Action Allow
    
  4. 禁用服务器端 TCP 自动调优

    netsh int tcp set global autotuninglevel=disabled
    

树莓派系统级优化:

  1. 更新内核和固件:

    sudo apt update && sudo apt full-upgrade -y
    sudo rpi-update
    
  2. 调整网络缓冲:

    # /etc/sysctl.conf 追加
    net.core.rmem_max=1048576
    net.core.wmem_max=1048576
    
  3. 使用固定 IP(避免 DHCP 续期干扰)

    # /etc/dhcpcd.conf
    interface eth0
    static ip_address=192.168.x.xx/24
    static routers=192.168.x.1
    

替代方案:使用更稳定的 smbclient

如果以上方案仍不稳定,建议使用系统级 smbclient:

import subprocess

def samba_client_command():
    cmd = [
        'smbclient',
        f'//{server_ip}/{share_name}',
        '-U', f'{username}%{password}',
        '-W', domain,
        '-c', 'ls'  # 可替换为其他命令
    ]
    
    try:
        result = subprocess.run(cmd, check=True, capture_output=True)
        return result.stdout.decode()
    except subprocess.CalledProcessError as e:
        print(f"Error: {e.stderr.decode()}")

# 使用示例
print(samba_client_command())

问题根源分析:

可能原因 解决方案 验证方法
SMB 协议版本不兼容 启用协议签名 Wireshark 抓包分析
Windows 防火墙阻断 添加永久防火墙规则 Test-NetConnection 192.168.x.x -Port 445
网络设备会话超时 调整 TCP keepalive echo 300 > /proc/sys/net/ipv4/tcp_keepalive_time
Windows TCP 自动调优 禁用 autotuning PowerShell 执行状态检查
凭证认证失败 使用本地账户替代微软账户 创建专用 SMB 用户

通过这些综合方案,95% 的 ConnectionReset 错误可被解决。对于生产环境,建议添加消息队列或连接池管理长期连接。

posted @ 2025-07-26 11:06  蓝莓薄荷  阅读(88)  评论(0)    收藏  举报