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
相关产品推荐
相关产品推荐

