You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python使用smbclient读取SMB文件时read()阻塞问题排查与解决求助

Python使用smbclient读取SMB文件时read()阻塞问题排查与解决求助

大家好,我现在在开发一个Python程序,要实现从GCP Bucket(通过Pub/Sub触发)到SMB/NFS共享存储的文件复制功能。目前用smbclient库的stat、makedirs和open_file方法搞定了文件写入的逻辑(因为处理的是CSV文件,所以用了wb/rb模式,这类文件没有EOF标记),但现在碰到了一个非常头疼的问题:在Docker容器里运行时,调用remote_file.read()读取SMB上的文件会直接卡住,完全没响应。

我先说说已经排查过的点:

  • 之前光是搞定smbclient的写入功能就费了好大劲,这个库加SMB协议本身确实让人头大
  • 检查过服务器时间:NFS服务器是PST时区,Docker容器是GMT时区,实际时间基本同步,只差一分钟左右
  • 网上几乎找不到靠谱的实战示例,smbprotocol的官方文档也很简陋,参考价值很低

下面是我的核心代码片段:

计算MD5的工具函数

def sign_md5_base64_from_file(content):
    md5_hash = hashlib.md5()
    
    chunk_size = 4096
    for i in range(0, len(content), chunk_size):
        md5_hash.update(content[i:i + chunk_size])
    
    return base64.b64encode(md5_hash.digest()).decode('utf-8')

文件上传与对比的核心逻辑

def send_file(chemin_samba):
    # [变量初始化逻辑]
    try:
        smbclient.stat(fullname_csv)
        fichier_existe = True
    except smbprotocol.exceptions.SMBOSError as e:
        if e.ntstatus == "0xc0000034":
            fichier_existe = False 
        else:
            print(f"An error occurred: {e}")
    
    smbclient.makedirs(dossier_destination, exist_ok=True)

    if fichier_existe:
        time.sleep(1)
        with smbclient.open_file(fullname_csv, mode="rb", share_access="r") as remote_file:
            remote_content = remote_file.read()  # 就是这一步卡住!
            samba_md5 = utils.sign_md5_base64_from_file(remote_content)
        
        local_md5 = utils.sign_md5_base64_from_file_path(variables.CHEMIN_CSV_LOCAL)
        
        if local_md5 == samba_md5:
            return
        else:
            # [文件不一致时的处理逻辑,原代码未完全贴出]
            pass
    else:
        logger.info(f"Ecriture du fichier CSV dans le répertoire distant - fullname : {fullname_csv} - nom du csv : {nom_csv}")
        with open(variables.CHEMIN_CSV_LOCAL, "rb") as local_file:
            with smbclient.open_file(fullname_csv, mode="wb") as remote_file:
                remote_file.write(local_file.read())
        logger.info(f"Fichier {nom_csv} envoyé avec succès à {chemin_samba}.")

卡住时的日志输出

INFO:file_sender: makedirs OK
INFO:smbprotocol.open:Session: nfs_smb OK, Tree Connect: 
DEBUG:smbprotocol.transport:Socket recv() returned 4 bytes (total 4)
DEBUG:smbprotocol.transport:Socket recv(160) (total 160)
DEBUG:smbprotocol.transport:Socket recv() returned 160 bytes (total 160)
DEBUG:smbprotocol.transport:Socket recv(4) (total 4)
INFO:smbprotocol.open:Session: nfs_smb_truenas, Tree Connect:  - receiving SMB2 Close Response
INFO:file_sender: download file
INFO:smbprotocol.open:Session: , Tree Connect: nfs_smb - receiving SMB2 Create Response
DEBUG:smbprotocol.transport:Socket recv() returned 4 bytes (total 4)
DEBUG:smbprotocol.transport:Socket recv(152) (total 152)
DEBUG:smbprotocol.transport:Socket recv() returned 152 bytes (total 152)
DEBUG:smbprotocol.transport:Socket recv(4) (total 4)
DEBUG:smbprotocol.open:SMB2CreateResponse:
    structure_size = 89
    oplock_level = (0) SMB2_OPLOCK_LEVEL_NONE
    flag = 0
    create_action = (1) FILE_OPENED
    creation_time = 2024-12-12 10:23:27.226642+00:00
    last_access_time = 2024-12-12 10:23:27.226642+00:00
    last_write_time = 2024-12-12 10:23:27.234844+00:00
    change_time = 2024-12-12 10:23:27.234844+00:00
    allocation_size = 45568
    end_of_file = 44909
    file_attributes = (32) FILE_ATTRIBUTE_ARCHIVE
    reserved2 = 0
    file_id = 3D D2 B6 EF 00 00 00 00 13 DF 5B 6B 00 00 00 00
    create_contexts_offset = 0
    create_contexts_length = 0
    buffer = []

    Raw Hex:
        
INFO:file_sender:Open SMB RB OK
DEBUG:smbclient._io:Read 0 -65536.
INFO:smbprotocol.open:Session: nfs_smb_truenas, Tree Connect ID: NAS SMB
DEBUG:smbprotocol.transport:Socket recv() returned 4 bytes (total 4)
DEBUG:smbprotocol.transport:Socket recv(44989) (total 44989)
DEBUG:smbprotocol.transport:Socket recv() returned 13028 bytes (total 44989)
DEBUG:smbprotocol.transport:Socket recv(31961) (total 44989)

# 日志到这里完全卡住,直到Docker超时或我手动停掉容器

SMB服务器上的文件锁状态

卡住后,SMB服务器上会出现持续的文件锁,直到我停掉Docker容器才会释放:

[~] smbstatus -L
Locked files:
Pid          User(ID)   DenyMode   Access      R/W        Oplock           SharePath   Name   Time
---------------------------------------------------------------------------
58763        1000       DENY_WRITE 0x89        RDONLY     NONE             /mnt/pool1/nfs_smb   path_to_file/test.csv    date PST

从日志和现象来看,代码100%卡在remote_file.read()这一步。我的核心需求其实很明确:

  1. 检查SMB上是否存在目标文件
  2. 存在的话读取文件计算MD5,和本地文件MD5对比,一致就跳过复制
  3. 不存在的话创建目录,然后上传本地文件

现在卡在读取文件这一步完全动不了,有没有大佬遇到过类似的问题?或者能给我一些调试方向?比如是不是read()的调用方式有问题?或者SMB共享的配置需要调整?

备注:内容来源于stack exchange,提问作者H C

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:39:36