需要解释读取和命名管道的行为
Need to explain behavior of read and named pipe
我一直在为大学做项目,在里面我有一些小脚本可以对一个简单的数据库执行操作(比如 select 信息),一个服务器脚本,它接受来自各种实例的请求通过名为 server.pipe 的管道的客户端脚本和通过单个客户端的命名管道 returns 它们的结果(通常是文本文件的几行)。
对于多行响应,我尝试在客户端中使用 while 循环来继续从管道读取数据,我使用了这样的方法:
read response < $id.pipe
while [ $response != "end_result" ]; do
echo $response
read response < $id.pipe
这有时会 return 完整结果,有时会 return 一部分,有时 none。当它没有 return 完整结果时,我认为 运行 脚本被管道阻塞,因为调试语句显示它没有执行它的最后几行。
我改用这个修复了它
tail <$return_pipe &
我知道 tail 会从管道读取,即使它关闭了,但我需要帮助解释导致第一个失败的条件,因为我现在正在写一份关于任务的报告。我读了很多书,有点明白了,但我需要有关细节的帮助。
如果有人想知道,服务器脚本是这样调用脚本的:
return_pipe=${ar[4]}.pipe
./select.sh ${ar[1]} ${ar[2]} ${ar[3]} >$return_pipe &
select 脚本的一部分 return 结果是这样的
echo "start_result"
cut -d' ' -f .//
echo "end_result"
如果有人能帮助我理解并解释它,我将不胜感激。这是我的第一个 post 所以我希望我也适当地格式化了它!谢谢
发生这种情况是因为 fifo 不是面向数据包的。这是一个流。
这意味着多个写入可能会在内存中串联,并且在不读取所有管道缓冲区的情况下关闭管道将丢弃剩余部分。
这是否会发生是一个竞争条件。以下是有效的事件顺序:
- 服务器打开 msg1 的 fifo
- 客户端打开 msg1 的 fifo
- 服务器写入 msg1
- 服务器关闭fifo
- 客户端读取msg1
- 客户端关闭fifo
- msg2
以相同的顺序重复上述内容
这是一个代码示例,其中包含用于确保良好顺序的睡眠:
rm fifo; mkfifo fifo
{
echo "hello" > fifo
sleep 1
echo "world" > fifo
} &
for i in 1 2
do
echo "Reading..."
{ read var; } < fifo
sleep 1
echo "Read: $var"
done
这将输出您所期望的:
Reading...
Read: hello
Reading...
Read: world
这是失败事件的顺序:
- 服务器打开 msg1 的 fifo
- 客户端打开 msg1 的 fifo
- 服务器写入msg1并关闭fifo
- 服务器打开 msg2 的 fifo
- 服务器写入msg2并关闭fifo
- 客户端读取msg1
- 当 msg2 仍未读时,客户端关闭了 fifo。 msg2 现在丢失了。
这里有一些睡眠可以实现这一点:
rm fifo; mkfifo fifo
{
echo "hello" > fifo
echo "world" > fifo
} &
for i in 1 2
do
echo "Reading..."
{ sleep 1; read var; } < fifo
echo "Read: $var"
done
现在它将打印:
Reading...
Read: hello
Reading...
并挂起,因为 world
丢失了。
您应该从客户端和服务器打开一次 fifo,并继续写入同一个打开的 FD。这样可以确保通信顺畅高效,不会丢失任何数据。
我一直在为大学做项目,在里面我有一些小脚本可以对一个简单的数据库执行操作(比如 select 信息),一个服务器脚本,它接受来自各种实例的请求通过名为 server.pipe 的管道的客户端脚本和通过单个客户端的命名管道 returns 它们的结果(通常是文本文件的几行)。
对于多行响应,我尝试在客户端中使用 while 循环来继续从管道读取数据,我使用了这样的方法:
read response < $id.pipe
while [ $response != "end_result" ]; do
echo $response
read response < $id.pipe
这有时会 return 完整结果,有时会 return 一部分,有时 none。当它没有 return 完整结果时,我认为 运行 脚本被管道阻塞,因为调试语句显示它没有执行它的最后几行。
我改用这个修复了它
tail <$return_pipe &
我知道 tail 会从管道读取,即使它关闭了,但我需要帮助解释导致第一个失败的条件,因为我现在正在写一份关于任务的报告。我读了很多书,有点明白了,但我需要有关细节的帮助。
如果有人想知道,服务器脚本是这样调用脚本的:
return_pipe=${ar[4]}.pipe
./select.sh ${ar[1]} ${ar[2]} ${ar[3]} >$return_pipe &
select 脚本的一部分 return 结果是这样的
echo "start_result"
cut -d' ' -f .//
echo "end_result"
如果有人能帮助我理解并解释它,我将不胜感激。这是我的第一个 post 所以我希望我也适当地格式化了它!谢谢
发生这种情况是因为 fifo 不是面向数据包的。这是一个流。
这意味着多个写入可能会在内存中串联,并且在不读取所有管道缓冲区的情况下关闭管道将丢弃剩余部分。 这是否会发生是一个竞争条件。以下是有效的事件顺序:
- 服务器打开 msg1 的 fifo
- 客户端打开 msg1 的 fifo
- 服务器写入 msg1
- 服务器关闭fifo
- 客户端读取msg1
- 客户端关闭fifo
- msg2 以相同的顺序重复上述内容
这是一个代码示例,其中包含用于确保良好顺序的睡眠:
rm fifo; mkfifo fifo
{
echo "hello" > fifo
sleep 1
echo "world" > fifo
} &
for i in 1 2
do
echo "Reading..."
{ read var; } < fifo
sleep 1
echo "Read: $var"
done
这将输出您所期望的:
Reading...
Read: hello
Reading...
Read: world
这是失败事件的顺序:
- 服务器打开 msg1 的 fifo
- 客户端打开 msg1 的 fifo
- 服务器写入msg1并关闭fifo
- 服务器打开 msg2 的 fifo
- 服务器写入msg2并关闭fifo
- 客户端读取msg1
- 当 msg2 仍未读时,客户端关闭了 fifo。 msg2 现在丢失了。
这里有一些睡眠可以实现这一点:
rm fifo; mkfifo fifo
{
echo "hello" > fifo
echo "world" > fifo
} &
for i in 1 2
do
echo "Reading..."
{ sleep 1; read var; } < fifo
echo "Read: $var"
done
现在它将打印:
Reading...
Read: hello
Reading...
并挂起,因为 world
丢失了。
您应该从客户端和服务器打开一次 fifo,并继续写入同一个打开的 FD。这样可以确保通信顺畅高效,不会丢失任何数据。