linux - 如何让 bash FIFO 等到它完成从另一端的读取?

标签 linux bash fifo

我正在编写一个 bash 脚本,我正在寻找可以让我将命令发送到程序将读取和执行的文件的东西。我找到了this .从一开始我开始实验我就意识到有一个大麻烦:如果输入行大约有 100 个字符,那么从另一端读取失败的可能性约为 50%。让我举例说明会发生什么。

首先,我们需要一个 fifo 和两个分别用于服务器和客户端的单线。

# creating fifo
mkfifo pipe

# a-la server
while true; do \
    echo -n 'Send to client: > ';\
    read ;\
    echo "$REPLY" > pipe ;\
    read answer < pipe ;\
    echo "Got answer: $answer" ;\
done

# a-la client
while read < pipe; do \
    echo 'Finished reading.';\
    echo "FROM SERVER: $REPLY" ;\
    echo ACK > pipe ;\
done

假设我们在 $HOME 中完成了所有这些操作,则无需检查管道是否存在。所以,在像“123”或“错误在哪里?”这样的简单情况下,一切正常。但是,如果您尝试从维基百科上的任何文章中复制一个五行的段落并将其发送给客户端,它将失败。

我们可以获得的示例:

服务器:

Send to client: > 123
Got answer: ACK
Send to client: > авление Вашаклахуун-Уб’аах-К’авииля отметилось возведением множества построек в столице царства. Были сооружены Храм 16, Храм 20, Храм 21, Храм 22 (посвящённый двадцатилетию со дня коронации этого правителя[31]), окончательная версия местного стадиона для игры в мяч, а также святилище Эсмеральда, украшенное большой Иероглифической лестницей, излагающей историю Шукуупа. Стоит также отметить, что при Вашаклахуун-Уб’аах-К’авииле резко изменился стиль в монументальной скульптуре. Его стелы, установленные после 710 года (а именно Стелы C, F, 4, H, A, B и D), отличаются пластичностью и раскованно
Got answer: ÐÐм множе²°ÐÐÑÑÑÐÐÐ ²ÑÑÐÐÐÑÐ °²° »¸ÑÐÐÑÑÐÐÐÑ ¥°¼1,ÐÑÐÐ 0 ¥°¼2,ÐÑÐÐ 2(¿¾²½½¹ÐÐÐÐÑÐÑÐÐÐÑÐÑÑÐ ÐÐÑ º¾¾½°¸¸ÑÑÐÐÐ ¿°²¸µ»3], ÐÐÐÐÑÐÑÐÐÑÐÐÑ ²µ¸ÐÐÑÑÐÐÐÐ °´¸¾½°ÐÐÑ ¸³Ð ¼ °ÑÐÐÐÐ ²¸»¸µÐÑÐÐÑÐÐÑÐÐ,ÑÐÑÐÑÐÐÐÐÐ ±¾»¾¹ÐÐÑÐÐÐÐÑÐÑÐÑÐÐÐ »µ½¸µ¹ ¸·»°³°щµ¹ÐÑÑÐÑÐÑ ¨º¿° ¡¾¸ÑÐÐÐÐ ¾¼µ¸ ¾ÐÑÐ °°º»°½ÐÐ♰°Ð♰²¸¸»µÑÐÐÐÐ ¸·¼µ½¸»ÑÑлÐ ¼¾½¼µ½°»½¾¹ÑÐÑÐÑÐÑÑÑÐ.ÐÐÐ µ»ы, устан¾²»µ½½µÐÐÑÐÐ 1 ³¾´°(°ÐÐÐÐÐÐ ¡µ»C ,4 ,A  ¸D,ÐÑÐÐÑÐÑÑÑÑ ¿»°¸½¾Ð °º¾ÐÐÐÐ
Send to client: >

在客户端只有:

Finished reading.
FROM SERVER: 123

看起来服务器在发送数据后立即开始读取,因此客户端几乎无法从管道中读取内容。在上面的例子中,他无法阅读任何内容。而这一切也破坏了多字节编码的文本。

简单来说就是这样

  1. 服务器发送:aaaaaaaa… -this is a very long line - …aaaaaabcbcbcbc
  2. 服务器读取:aaaa… …abcbbc
  3. /实际上与#2/客户端同时读取服务器尚未读取的内容:aaccb

为了让服务器在尝试从客户端读取“ACK”之前等待,我尝试更改管道的文件权限,使它们充当信号量。结果很有趣。

由于我们无法操纵读取权限(因为一旦服务器禁止,客户端将无法从管道读取)我们将切换 -w旗帜。

这里是客户端和服务器的修改版本。 NB 在客户端读取命令后更改重定向。

# a-la server
chmod 644 pipe ;\
while true; do \
    echo -n 'Send to client: > ';\
    read ;\
    echo "$REPLY" > pipe ;\
    chmod -w pipe ;\
    until [ -w pipe ]; do \
        echo 'Waiting client to read what we sent' ;\
        sleep 1 ;\
    done ;\
    read answer < pipe ;\
    echo "Got answer: $answer" ;\
done

# a-la client
chmod 644 pipe ;\
set -x ;\
while read <>pipe; do \
    echo 'Finished reading.' ;\
    chmod u+w pipe ;\
    echo $? ;\
    ls -l pipe &>/dev/null ;\
    echo "FROM SERVER: $REPLY" ;\
    echo ACK > pipe ;\
done

chmod 644在这里是为了确保管 Prop 有正确的权限,无论您先启动哪个脚本。

set -x为了看到那里的乐趣。

客户端中的重定向更改为 <>由于管道上的读写锁。我不确定它们是如何工作的,但是在客户端上阅读 read <pipe在服务器上禁用写权限后不起作用。

确保您的段落足够大,以便执行回显“等待客户端读取我们发送的内容”的代码。

我实际上不会发送那么大数据,我只是认为 I/O 中的意外延迟可能是这个错误甚至出现在短短语上的原因。

现在的问题是:为什么,如果您删除 ls命令,它停止处理大数据?

我的 bash 版本:GNU bash, version 4.2.45(1)-release (x86_64-pc-linux-gnu)

最佳答案

命名管道只是一种单向通信流:任何进程写入其中的任何内容都会被某个进程读出。您有两个进程(服务器和客户端)写入其中,并且有两个进程从中读取,因此您无法保证哪个进程看到哪个输入。

您想要双向通信:您希望您的客户端只看到服务器写入的内容,而您的服务器只看到客户端写入的内容。为此,您需要创建两个命名管道:一个是服务器写入,客户端从中读取,另一个是客户端写入,服务器从中读取。

关于linux - 如何让 bash FIFO 等到它完成从另一端的读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21082420/

相关文章:

linux - 恢复已删除的容器docker

bash - 在 shell for 循环中移动文件时出错

Bash:出错时退出并清理

regex - 如何以复杂模式 grep 日期?

java - 如何保证 ThreadPoolExecutor 中的 FIFO 执行顺序

将数据从内核空间复制到用户空间

linux - 防止从静态库导入函数

linux - 发送最近的文件附件

python - 在 Python 中丢弃具有最大容量的 FIFO 队列?

c - 如何用C不断读取FIFO