连续写入命名管道

TJJ*_*TJJ 0 pipe shell-script fifo

我有一个涉及两个命名管道的问题似乎无法解决。基本上,我有两个无法控制的流程。他们通过命名管道 ( ) 进行通信mknod pipe p。进程一是 GPS 驱动程序,以 NMEA0183 格式输出消息。流程二是一个导航应用程序,它读取 NMEA0183 数据以从 GPS 获取位置和日期/时间。我需要调整此数据(原因:谷歌搜索 WNRO 或询问)。

  1. 第一个进程以 1 秒的间隔连续将数据(约 5-8 行文本)写入 /var/run/one.pipe 并将其留在那里直到被读取(?)

  2. 第二个进程是从命名管道读取此数据。我可以更改要读取的命名管道的名称。我将其更改为 /var/run/two.pipe

最终目标是从 one.pipe 读取数据,进行一些处理,然后将其传递给 Two.pipe。然而,与此同时,为了进行测试,我只是尝试将数据从 one.pipe 逐一复制到 Two.pipe。我认为在整个处理过程中浪费时间是不可行的,直到我能够完成这个(更简单的?)任务。

一个非常简单的 shell 脚本可以工作:copy.sh

#!/bin/sh
cat one.pipe > two.pipe &
Run Code Online (Sandbox Code Playgroud)

现在我捕获了源进程写入的一些数据one.pipe,并尝试手动将其写入two.pipe以供读取进程读取:

#!/bin/sh

while true; do
  echo "\$GPGGA,,,,,,,,*12" > two.pipe
  echo "\$GPGSA,,,,,,,,*23" > two.pipe
  echo "\$GPRMC,,,,,,,,*34" > two.pipe
  echo "\$GPGSV,,,,,,,,*45" > two.pipe
  echo "\$GPGSV,,,,,,,,*56" > two.pipe
  echo "\$GPGSV,,,,,,,,*67" > two.pipe
  # checksums (*xx) are just examples here
  sleep 1 > two.pipe
done
Run Code Online (Sandbox Code Playgroud)

现在这效果不太好。如果我cat one.pipe与进行比较,cat two.pipe我可以看到 中的消息two.pipe不会“堆积”,而它们是从写入 的原始进程中堆积起来的one.pipe。例如,如果我启动脚本,它应该写入命名管道并继续这样做。当我用它读取该管道时,cat应该输出到目前为止的所有数据(假设 fifo 缓冲区尚未填充)。毕竟是先进先出,不是吗?

此外,cat 现在经常看似随机地停止。最后,我无法控制正在读取的进程two.pipe似乎无法很好地处理数据/导致脚本终止。

我什至不明白为什么脚本会终止,即使它包含无限循环?!

我在这里监视什么?如果用 shell 编写不可行,C 也是一个选择。

小智 5

while true; do
  echo "\$GPGGA,,,,,,,,*12" > two.pipe
  echo "\$GPGSA,,,,,,,,*23" > two.pipe
  ...
Run Code Online (Sandbox Code Playgroud)

... > two.pipe脚本中的每一行都将打开和关闭fifo two.pipe,关闭它可能会导致从管道另一端进行的任何读取返回文件结尾,然后退出cat

我建议首先为整个脚本打开 fifo一次exec

#!/bin/sh

exec > two.pipe

while true; do
  echo "\$GPGGA,,,,,,,,*12"
  echo "\$GPGSA,,,,,,,,*23"
  ...
  sleep 1
done
Run Code Online (Sandbox Code Playgroud)

您可以通过将 fifo 的两端打开到同一个句柄中来“固定”fifo,例如。

exec 7<>two.fifo
Run Code Online (Sandbox Code Playgroud)

只要执行此操作的进程尚未退出并且未关闭文件描述符,就可以确保当其写​​入7端的所有其他句柄都已关闭时,从中读取的进程不会收到文件结束符。关闭,并且当其读取端的所有其他句柄都关闭时,写入它的进程不会被 a 杀死。SIGPIPE

此外,同时打开指定 fifo 的两端也不会阻塞。