【问题标题】:How to detect pclose inside client如何检测客户端内部的pclose
【发布时间】: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) 刷新它——并且不要忽略fwritefflush 的返回值。如果fwrite()printf()、puts() 等缓存了任何数据,fflush(stdout) 应该最终调用write() 系统调用,并且在没有读取器的情况下写入管道将触发SIGPIPE 或失败errno 设置为EPIPE(后者是在有人愚蠢地将SIGPIPE 处置设置为“忽略”的情况下)。
  • @WilliamPursell ... 或进程的任何父进程已将SIGPIPE 处置设置为“忽略”,这是通过分叉和执行程序继承的。
  • 您也可以考虑实现自己的替代popen,在完成后终止客户端进程。见:stackoverflow.com/questions/6743771/popen-alternative

标签: c linux pipe popen


【解决方案1】:

三种方式:

  1. 如果您正在从管道读取数据,而另一端消失了,您应该得到文件结尾,并且您可以检测到它并停止。
  2. 如果您正在从管道读取数据并且您控制协议,那么另一端可以通过管道向您发送“退出”命令,您可以读取该命令并停止。
  3. 如果您正在写入管道,而另一端消失了,您应该会收到一个 SIGPIPE 信号,默认情况下应该会终止您的进程。

请注意,#1 仅在另一端是唯一打开管道的进程时才有效。如果任何其他进程打开了管道的写入端,您将不会得到 EOF,并且您不会知道停止。如果您调用pipe(),然后是exec() 很容易打开管道的写入端。这是一个常见的错误。 (不过,由于您拨打的是popen(),因此您遇到此问题的可能性较小。)

【讨论】:

  • 这两个读取选项“不适用于”进程正在写入的问题——但它们是一般答案的一部分。第四种选择是写入过程忽略 SIGPIPE,因此写入将失败并出现错误(EINTR?),而不是生成忽略的信号。
  • 好的。 3.似乎是我的解决方案。如何检查 SIGPIPE 信号?
  • @wolfgang6444 除非你正在做一些特别的事情,否则你不应该做任何事情——默认情况下 SIGPIPE 会终止你的进程。只有当您(或代表您的某人)捕获或忽略了 SIGPIPE 时,您才需要做一些事情,以便您可以明确地捕获或取消忽略它。
  • 好的。 - 所以我必须检查 API 是否真的在客户端调用 pclose。
猜你喜欢
  • 2011-03-01
  • 2011-09-13
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-25
相关资源
最近更新 更多