Как заставить несколько процессов "общаться" вместе?

Я пытаюсь смоделировать игру для двух игроков в bash. Точнее, должна быть одна центральная программа (движок игры) и две программы для игроков. Игровой движок должен отправить информацию об игре в 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 ответ

Решение

Вот некоторые изменения, которые могут продвинуть вас дальше:

  • в первом сценарии есть опечатка. Так должно быть:

    ./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

Чтение будет блокироваться до "привет", затем цикл с кодом возврата "1".

Другие вопросы по тегам