如何使bash FIFO等待,直到它完成从另一侧的读取



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

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

# 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在这里是为了确保无论您先启动哪个脚本,管道都具有正确的权限。

set -x,看看那里会有什么乐趣。

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

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

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

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

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

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

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

最新更新