如何让多个进程一起 "chat"?

How to get several processes to "chat" together?

我正在尝试在 bash 中模拟 2 人游戏。更准确地说,应该有一个中央程序(游戏引擎)和两个玩家程序。游戏引擎应该将游戏信息发送给玩家1,然后获取玩家1的输出,然后将游戏信息发送给玩家2,然后获取玩家2的输出,并重复。

如果可能的话,我更希望游戏引擎不负责调度其输出,而是依靠 bash 脚本来安排整个事情。

在阅读了有关命名管道的内容后,我认为它们正是我所需要的,并提出了以下设置:

#!/bin/bash

trap "rm -f $in1 $in2 $out1 $out2 $in $out; kill $pid; kill $pid1; kill $pid2" KILL

in1=/tmp/testpipe_in1
in2=/tmp/testpipe_in2
out1=/tmp/testpipe_out1
out2=/tmp/testpipe_out2
in=/tmp/testpipe_in
out=/tmp/testpipe_out

for p in $in1 $in2 $out1 $out2 $in $out; do
    [[ -p $p ]] || mkfifo $p
done

echo 0 > $in
./center.sh < $in > $out &
pid=$!
./player1.sh < $in1 > $out2 &
pid1=$!
./player2.sh < $in2 > $out2 &
pid2=$!

i=0
while true; do
    i=$((i+1))
    echo "Round $i" >&2
    cat < $out > $in1
    cat < $out1 > $in
    cat < $out > $in2
    cat < $out2 > $in
done

我正在使用以下游戏和玩家进行测试:

center.sh:

#!/bin/bash

while true; do
    sleep 2
    read i
    echo "Center : $i $((i+2))" >&2
    echo $((i+2))
done

player1.sh:

#!/bin/bash

while true; do
    sleep 1
    read i
    echo "Player1 : $i $((i-1))" >&2
    echo $((i-1))
done

player2.sh:

#!/bin/bash

while true; do
    sleep 1
    read i
    echo "Player2 : $i $((i+1))" >&2
    echo $((i+1))
done

我希望它输出类似

的内容
Center : 0 2
Round 1
Player1 : 2 1
Center : 1 3
Player2 : 3 4
Center : 4 6
Round 2
Player1 : 6 5
...

...不过当然不行了

相反,我得到:

Round 1
Center : 0 2
Center :  2
Center :  2
...

问题是否在我的播放器中很明显?或者设置这种 inputs/outputs 调度的正确方法是什么?

下面是一些可能会让您更进一步的更改:

  • 您的第一个脚本中有错字。应该是:

    ./player1.sh < $in1 > $out1 &
    

即out1 不是 out2。

  • echo 0 > $in移动到开始播放器后

  • 将最后的 while 循环更改为:

      while true; do
          i=$((i+1))
          echo "Round $i" >&2
          read <&5; echo "$REPLY" >&6
          read <&7; echo "$REPLY" >&8
          read <&5; echo "$REPLY" >&9
          read <&4; echo "$REPLY" >&8
      done 5<$out 6>$in1 7<$out1 8>$in 9>$in2 4<$out2
    

最初,fifo 的 reader 被阻塞,直到写入程序写入 先进先出。一旦 writer 关闭 fifo,reader 读取 eof 但 不再阻塞所以继续读取eof直到作者重新打开 fifo 并再次写入。 您需要检查 read 的 return 代码并重新打开 fifo 作为 reader 为了再次阻止。

您可以通过以下方式轻松查看:

while sleep 1; do read;echo "$? $REPLY";done  <testpipe_out1 &
sleep 5
echo hi >testpipe_out1

读取将阻塞直到 "hi",然后循环使用 return 代码“1”。