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

Windows下Python mmap全局命名空间权限拒绝问题求助

解决Windows全局内存映射文件的客户端权限拒绝问题

问题背景

原本本地命名空间下的内存映射代码(tagname='test')可正常运行,但将tagname改为r'Global\test'后,普通用户运行客户端会触发PermissionError: [WinError 5] Access is denied。即使将服务器做成Windows服务运行(可正常创建全局映射),客户端仍无法访问。

解决方案

核心是服务器创建全局文件映射对象时,显式设置允许普通用户访问的安全权限。Windows服务进程创建的对象默认权限严格,需通过安全描述符开放权限给所有用户。

修改后的服务器代码

from mmap import mmap, ACCESS_WRITE
from pickle import load, dump
import ctypes
from ctypes import wintypes

# 加载Windows系统API
kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)
advapi32 = ctypes.WinDLL('advapi32', use_last_error=True)

# 定义安全描述符相关结构
class SECURITY_DESCRIPTOR(ctypes.Structure):
    _fields_ = [
        ('Revision', wintypes.BYTE),
        ('Sbz1', wintypes.BYTE),
        ('Control', wintypes.DWORD),
        ('Owner', wintypes.LPVOID),
        ('Group', wintypes.LPVOID),
        ('Sacl', wintypes.LPVOID),
        ('Dacl', wintypes.LPVOID),
    ]

class SECURITY_ATTRIBUTES(ctypes.Structure):
    _fields_ = [
        ('nLength', wintypes.DWORD),
        ('lpSecurityDescriptor', wintypes.LPVOID),
        ('bInheritHandle', wintypes.BOOL),
    ]

# 初始化安全描述符,允许所有用户读写
sd = SECURITY_DESCRIPTOR()
advapi32.InitializeSecurityDescriptor(ctypes.byref(sd), 1)  # 1对应SECURITY_DESCRIPTOR_REVISION
# 设置DACL为空,允许所有访问权限
advapi32.SetSecurityDescriptorDacl(ctypes.byref(sd), True, None, False)

sa = SECURITY_ATTRIBUTES()
sa.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES)
sa.lpSecurityDescriptor = ctypes.byref(sd)
sa.bInheritHandle = False

# 创建全局文件映射对象
INVALID_HANDLE_VALUE = wintypes.HANDLE(-1).value
h_map = kernel32.CreateFileMappingW(
    INVALID_HANDLE_VALUE,  # 使用系统页交换文件
    ctypes.byref(sa),      # 传入配置好的安全属性
    0x04,                  # 读写权限
    0,                     # 文件最大尺寸高位
    32,                    # 文件最大尺寸低位
    r'Global\test'         # 全局命名空间的映射名称
)

if not h_map:
    raise ctypes.WinError(ctypes.get_last_error())

# 用mmap包装句柄,实现原有逻辑
mm = mmap(h_map, length=32, access=ACCESS_WRITE)

last_request_id = None
try:
    while True:
        mm.seek(0)
        try:
            request_id = int(load(mm))
            if request_id != last_request_id:
                last_request_id = request_id
                print(request_id)
        except Exception:
            pass
finally:
    mm.close()
    kernel32.CloseHandle(h_map)

客户端代码(无需大幅修改)

from mmap import mmap
from pickle import dump

# 直接连接全局映射,权限已开放
with mmap(-1, 32, tagname=r'Global\test') as mm:
    request_id = 1
    dump(request_id, mm)

关键说明

  • 服务器通过CreateFileMappingW显式传入安全描述符,解除默认的严格权限限制,允许所有用户访问该全局映射对象
  • 安全描述符中设置空DACL是最简开放方式,生产环境可根据需求配置更精细的权限规则
  • 客户端只需正确指定全局命名空间的tagname,即可正常访问服务端创建的映射

内容的提问来源于stack exchange,提问作者Carlos Porta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 03:40:33