使用 pipe() 和 fdopen() 将数据从 Python 脚本传递到 Windows 中的 C++ 应用程序
Posted
技术标签:
【中文标题】使用 pipe() 和 fdopen() 将数据从 Python 脚本传递到 Windows 中的 C++ 应用程序【英文标题】:Use pipe() and fdopen() to pass data from Python script to C++ application in Windows 【发布时间】:2019-11-06 18:04:37 【问题描述】:我们有一些 Linux/macOS 应用程序,它可以通过传递文件描述符并从中读取数据来与外部世界通信。通常这样做是为了传递标准输入/标准输出描述符,但是我们使用 pipe() 并且效果很好。除了 MinGW/Windows。 在 Windows 下做同样工作的推荐方法是什么?传递整个文件句柄,或者有什么好方法可以模拟 small-int-like 描述符?
【问题讨论】:
您的 C++ 应用程序使用pipe
和 fdopen
?如果是这样,在 Windows 中,您可以使用 CreateProcess
并使用标准输入、标准输出和标准错误的文件句柄初始化 STARTUPINFO
结构。
@TedLyngmo 实际上 C++ 应用程序使用 fdopen() 并且 Python 脚本向它提供文件描述符编号,通过 os.pipe() 调用获得。所以 stdin/stdout/sterr 方法不会按预期方式工作。
啊...假设 python 端没问题,Windows _fdopen 可以工作吗?或者,您甚至无法访问文件描述符?
TedLyngmo:我从 Python 收到 fd = 3,并尝试使用 EBADF 打开它失败。 @ErykSun 感谢您提供详细信息!我们使用 Python 2.7。
@ErykSun 再次感谢。找到了寻找解释的方向并克服了这一点,这说明了很多:bugs.python.org/issue32865
【参考方案1】:
在 Windows 中,C 文件描述符在进程STARTUPINFO
中被继承,记录在保留字段cbReserved2
和lpReserved2
中。该协议未记录,但源代码与 Visual C++ 一起分发。使用此功能的 C 函数包括 _[w]spawn
系列函数和 [_w]system
。 (不过,[_w]system
函数在这方面通常没有用处,因为只有直接的 cmd.exe 进程会继承父进程的文件描述符。CMD 不会将它们传递给子进程。)
在 Python 2.7 中,os.pipe
是通过调用 CreatePipe
实现的,它为管道的读取和写入端返回不可继承的文件句柄。然后通过_open_osfhandle
使用可继承的文件描述符手动包装这些句柄,但底层操作系统句柄仍然是不可继承的。要解决此问题,请通过 os.dup
复制文件描述符,这会在内部复制可继承的文件句柄,然后关闭源文件描述符。例如:
pread, pwrite = os.pipe()
pwrite_child = os.dup(pwrite)
os.close(pwrite)
Python 的subprocess
模块通常是创建子进程的首选方式。但是,在这种情况下我们不能使用subprocess
,因为它不支持通过STARTUPINFO
(*) 继承文件描述符。下面是一个使用os.spawnv
的示例:
rc = os.spawnv(os.P_WAIT, 'path/to/spam.exe', ['spam', 'arg1', 'arg2'])
(*) Windows Python 内部使用 C 运行时文件 API(例如 _wopen
、_read
、_write
)是一个尴尬的情况,但在某些地方不支持 C 文件描述符。它应该咬紧牙关,直接使用 Windows 文件 API 与 OS 文件句柄,那么它至少会是一致的。
【讨论】:
使用这种方法工作的托管代码。问题的另一部分是 Python,使用 MSYS/MinGW 编译 - 它根本不起作用,而 Windows Python 安装运行良好。 MSYS/MinGW 版本的 lpReserved2 有不同的数据。以上是关于使用 pipe() 和 fdopen() 将数据从 Python 脚本传递到 Windows 中的 C++ 应用程序的主要内容,如果未能解决你的问题,请参考以下文章