如何让几个进程“一起”聊天?

时间:2015-08-28 06:54:20

标签: bash named-pipes

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

如果可能的话,我更喜欢游戏引擎不负责调度其输出,而是依靠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
...

问题在我的球员中是否显而易见?或者设置这种输入/输出的正确方法是什么?

1 个答案:

答案 0 :(得分:1)

以下是一些可能会让您更进一步的变化:

  • 你的第一个剧本中有一个拼写错误。它应该是:

    ./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的读者被阻止,直到作家写入 fifo。一旦作者关闭了fifo,读者就会阅读eof但是 不再被阻止所以继续阅读eof直到作者重新打开 fifo再次写道。 您需要检查read的返回码并重新打开fifo 作为读者,以便再次阻止。

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

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

读取将阻塞直到“hi”,然后循环返回代码“1”。