首页 > 解决方案 > pysmb 从 linux 到 Windows,无法连接到共享设备

问题描述

尝试通过连接到 smb 共享pysmb并出现错误...

smb.smb_structs.OperationFailure: Failed to list  on \\\\H021BSBD20\\shared_folder: Unable to connect to shared device

我正在使用的代码看起来像......

from smb.SMBConnection import SMBConnection
import json
import pprint
import warnings

pp = pprint.PrettyPrinter(indent=4)
PROJECT_HOME = "/path/to/my/project/"

# load configs
CONF = json.load(open(f"{PROJECT_HOME}/configs/configs.json"))
pp.pprint(CONF)

# list all files in storage smb dir
#https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html#smb.SMBConnection.SMBConnection.listPath
IS_DIRECT_TCP = False
CNXN_PORT = 139 if not IS_DIRECT_TCP else 445
LOCAL_IP = "172.18.4.69"
REMOTE_NAME = "H021BSBD20"  # exact name shown as Device Name in System Settings
SERVICE_NAME = "\\\\H021BSBD20\\shared_folder"
REMOTE_IP = "172.18.7.102"
try:
    conn = SMBConnection(CONF['smb_creds']['username'], CONF['smb_creds']['password'],
                         my_name=LOCAL_IP, remote_name=REMOTE_NAME,
                         use_ntlm_v2=True,
                         is_direct_tcp=IS_DIRECT_TCP)
    conn.connect(REMOTE_IP, CNXN_PORT)
except Exception:
    warnings.warn("\n\nFailed to initially connect, attempting again with param use_ntlm_v2=False\n\n")
    conn = SMBConnection(CONF['smb_creds']['username'], CONF['smb_creds']['password'],
                         my_name=LOCAL_IP, remote_name=REMOTE_NAME,
                         use_ntlm_v2=False,
                         is_direct_tcp=IS_DIRECT_TCP)
    conn.connect(REMOTE_IP, CNXN_PORT)

files = conn.listPath(f'{SERVICE_NAME}', '\\')
pp.pprint(files)

在我的机器上使用smbclient,我可以通过执行成功连接到共享...

[root@airflowetl etl]# smbclient -U my_user \\\\H021BSBD20\\shared_folder

我在 python 代码中使用的反斜杠数量是为了让我可以创建在使用它时可以使用的相同字符串smbclient(尝试在代码中使用更少的反斜杠,但没有帮助)。

请注意,我在 python 代码中使用访问共享文件夹的用户smbclient无法访问/登录到托管共享的实际机器(他们只被允许访问该特定共享文件夹,如图所示多于)。

有谁知道这里会发生什么?还有其他可以完成的调试步骤吗?

标签: pythonpysmb

解决方案


在 github repo 问题部分(https://github.com/miketeo/pysmb/issues/169)询问后,我能够解决问题。这只是由于我用于conn.listPath() servicename参数的 arg。

当仔细查看该功能的文档(https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html)时,我看到了......

service_name (string/unicode) – 路径的共享文件夹的名称

最初,我只查看函数签名,它说service_name,所以我认为它与smbclient命令行工具相同(我一直在输入servicename参数\\\\devicename\\sharename(不像pysmb我们可以从文档字符串中看到的那样想要)共享为service_name))。

所以而不是

files = conn.listPath("\\\\H021BSBD20\\shared_folder", '\\')

我愿意

files = conn.listPath("shared_folder", '\\')

完整的重构片段如下所示,仅供参考。

import argparse
import json
import os
import pprint
import socket
import sys
import traceback
import warnings

from smb.SMBConnection import SMBConnection


def parseArguments():
    # Create argument parser
    parser = argparse.ArgumentParser()
    # Positional mandatory arguments
    parser.add_argument("project_home", help="project home path", type=str)
    parser.add_argument("device_name", help="device (eg. NetBIOS) name in configs of share to process", type=str)
    # Optional arguments
    # parser.add_argument("-dfd", "--data_file_dir",
    #                     help="path to data files dir to be pushed to sink, else source columns based on form_type",
    #                     type=str, default=None)
    # Parse arguments
    args = parser.parse_args()
    return args


args = parseArguments()
for a in args.__dict__:
    print(str(a) + ": " + str(args.__dict__[a]))

pp = pprint.PrettyPrinter(indent=4)
PROJECT_HOME = args.project_home
REMOTE_NAME = args.device_name

# load configs
CONF = json.load(open(f"{PROJECT_HOME}/configs/configs.json"))
CREDS = json.load(open(f"{PROJECT_HOME}/configs/creds.json"))
pp.pprint(CONF)

SMB_CONFS = next(info for info in CONF["smb_server_configs"] if info["device_name"] == args.device_name)
print("\nUsing details for device:")
pp.pprint(SMB_CONFS)

# list all files in storage smb dir
#https://pysmb.readthedocs.io/en/latest/api/smb_SMBConnection.html#smb.SMBConnection.SMBConnection.listPath
IS_DIRECT_TCP = False
CNXN_PORT = 139 if IS_DIRECT_TCP is False else 445
LOCAL_IP = socket.gethostname()  #"172.18.4.69"
REMOTE_NAME = SMB_CONFS["device_name"]
SHARE_FOLDER = SMB_CONFS["share_folder"]
REMOTE_IP = socket.gethostbyname(REMOTE_NAME)  # "172.18.7.102"
print(LOCAL_IP)
print(REMOTE_NAME)
try:
    conn = SMBConnection(CREDS['smb_creds']['username'], CREDS['smb_creds']['password'],
                         my_name=LOCAL_IP, remote_name=REMOTE_NAME,
                         use_ntlm_v2=False,
                         is_direct_tcp=IS_DIRECT_TCP)
    conn.connect(REMOTE_IP, CNXN_PORT)
except Exception:
    traceback.print_exc()
    warnings.warn("\n\nFailed to initially connect, attempting again with param use_ntlm_v2=True\n\n")
    conn = SMBConnection(CREDS['smb_creds']['username'], CREDS['smb_creds']['password'],
                         my_name=LOCAL_IP, remote_name=REMOTE_NAME,
                         use_ntlm_v2=True,
                         is_direct_tcp=IS_DIRECT_TCP)
    conn.connect(REMOTE_IP, CNXN_PORT)

files = conn.listPath(SHARE_FOLDER, '\\')
if len(files) > 0:
    print("Found listed files")
    for f in files:
        print(f.filename)
else:
    print("No files to list, this likely indicates a problem. Exiting...")
    exit(255)

推荐阅读