【发布时间】:2019-07-25 16:02:56
【问题描述】:
通过 popen 启动并写入 stdout 的 C 客户端如何正确检测调用进程已调用 pclose。
我正在将二进制数据从一个用 C 编写的小型客户端程序发送到 Matlab。为此,Matlab 通过在用 C 编写的 API 中调用 popen 来启动该过程。客户端使用 fwrite 不断地将二进制数据写入标准输出。当 Matlab 停止时,API 显然在客户端的句柄上调用 pclose,但这不会停止客户端进程。我猜 fwrite 不会引发错误,因为数据会被操作系统缓冲。那么检测客户端内部pclose的合适方法是什么?
顺便说一句,当我尝试从 Matlab 中写入某个 C 客户端时,我会再次遇到同样的问题。
【问题讨论】:
-
调用进程关闭管道,然后等待c-client终止。 c-client 可以尝试写入并查找 SIGPIPE 信号,或者忽略 SIGPIPE 并发现写入错误。目前尚不清楚是否有其他方法可以找出答案。
-
如果您的客户端进程没有收到 SIGPIPE(我想这就是您所说的“fwrite ... rais[ing] 错误”的意思),那么很可能有一个文件描述符处于打开状态某处。
-
数据不是由操作系统缓冲,而是由 C 库的 stdio 部分缓冲。您应该使用
setvbuf()使标准输出无缓冲,或者在每个fwrite()之后使用fflush(stdout)刷新它——并且不要忽略fwrite或fflush的返回值。如果fwrite()、printf()、puts() 等缓存了任何数据,fflush(stdout)应该最终调用write()系统调用,并且在没有读取器的情况下写入管道将触发SIGPIPE或失败errno 设置为EPIPE(后者是在有人愚蠢地将SIGPIPE处置设置为“忽略”的情况下)。 -
@WilliamPursell ... 或进程的任何父进程已将
SIGPIPE处置设置为“忽略”,这是通过分叉和执行程序继承的。 -
您也可以考虑实现自己的替代
popen,在完成后终止客户端进程。见:stackoverflow.com/questions/6743771/popen-alternative