0

数百の組み合わせの後、クライアントからの応答を読み取るためのパイプを備えたサーバーとして 1 つのプロセスを使用する次のコードに至りました。私はそれを「london」関数と呼び、それをパイプ「london_pipe」と呼んでいます (パイプを「london」と呼ぶのは非常に不確かでした) ' も名前の競合のためですか?)。その下には、データを読み取るためにサーバーと独自のパイプで通信する 2 つのクライアントがあります。同じ命名規則に従い、パイプを読み取りに使用する関数の名前でパイプに名前を付けました。したがって、「berlin」は「berlin_pipe」などから読み取っています。

全体的な構造は、次のように、1 つのパイプ対 1 クライアントとサーバー用の 1 つのパイプを使用します。

london ----writes madrid pipe-------->
london <----reads london_pipe----<-  |
london ----writes berlin_pipe---> |  |
                                | ^  |
                                | |  |
berlin <---reads berlin_pipe--<-  |  |
berlin ----writes london_pipe-----|  |
                                  ^  |
                                  |  |
madrid ----writes london_pipe------  v
madrid <----reads madrid_pipe------<-

ここで、コードを実行すると、クライアントが空の文字列を繰り返し読み取り、プログラムを構成したときに、サーバーに誤ったアラームを送信して応答するという非常に奇妙な状況に直面します。if 句を追加すると (コードのコメントを参照)、問題はなくなりました。

私のパイプの奇妙な振る舞いを説明できる人はいますか? または、コード自体に一種の問題がありますか?

簡単に説明すると、コード

while true; do
.......
done 4<"$pipename"

fd 4 が毎回異なるパイプを指すように繰り返し使用されていたとしても、すべてのクライアントで機能します。今コード:

#!/bin/bash
shopt -u failglob
shopt -s extglob nullglob dotglob

DIR=$( cd "$( dirname "$0" )" && pwd )

#the server
function london (){
   local i message answer london_pipe berlin_pipe madrid_pipe
   london_pipe=london_$RANDOM.$RANDOM.$RANDOM.$$
   madrid_pipe=madrid_$RANDOM.$RANDOM.$RANDOM.$$
   berlin_pipe=berlin_$RANDOM.$RANDOM.$RANDOM.$$
   cd $DIR
   mkfifo $london_pipe
   mkfifo $madrid_pipe
   mkfifo $berlin_pipe
   ( madrid $madrid_pipe $london_pipe ) &
   ( berlin $berlin_pipe $london_pipe ) &
   i=0

   while true; do
      if [[ i -gt 100 ]]; then
         echo 'quit' > $madrid_pipe
         echo 'quit' > $berlin_pipe
         break
      else
         echo "loop #$i"
         echo '========='
         message="London loop (#$i)"

         #***send to Madrid***#
         echo "$message" > $madrid_pipe

         read -r answer <&3
         echo 'London says:> '"$answer"

         #***send to Berlin***#
         echo "$message" > $berlin_pipe

         read -r answer <&3
         echo 'London says:> '"$answer"
         (( i++ ))
      fi
   done 3< $london_pipe

   wait
   cd "$DIR"
   rm -rf $london_pipe
   rm -rf $madrid_pipe
   rm -rf $berlin_pipe
}

#a client
function berlin (){
   local i message answer berlin_pipe london_pipe
   berlin_pipe=$1
   london_pipe=$2
   cd $DIR
   i=0
   exec 3> $london_pipe
   while true; do

      read -r answer <&4
      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi
      echo 'Berlin says:> '"$answer"

      message="Greetings from Berlin!($i)"
      echo "$message" >&3
  (( i++ ))

      if [[ $answer = 'quit' ]]; then
         break
      fi
   done 4< "$berlin_pipe"
}

#another client
function madrid (){
   local i message answer madrid_pipe london_pipe
   madrid_pipe=$1
   london_pipe=$2
   cd $DIR
   i=0
   exec 3> $london_pipe
       while true; do

      read -r answer <&4
      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi
      echo 'Madrid says:> '"$answer"

      message="Greetings from Madrid!($i)"
      echo "$message" >&3
      (( i++ ))

      if [[ $answer = 'quit' ]]; then
         break
      fi
   done 4< "$madrid_pipe"
}

london

if-code はこのブロックです

      #***if deleted it reads empty strings!!!***#
      if [[ ! $answer ]]; then
         continue
      fi

これにより、いくつかの結果は次のとおりです。

loop #97
=========
Madrid says:> London loop (#97)
London says:> Greetings from Madrid!(97)
Berlin says:> London loop (#97)
London says:> Greetings from Berlin!(97)

なしで両方のクライアントに:

loop #91
=========
Madrid says:> London loop (#86)
Madrid says:> London loop (#87)
Madrid says:> London loop (#88)
Madrid says:> London loop (#89)
Madrid says:> London loop (#90)
Madrid says:> 
Madrid says:> 
Madrid says:> 

「madrid」がループ番号 86 などで「london」からのメッセージとともに空の文字列を読み取ったことは明らかです。これは以前の空の読み取りによってプッシュされ、現在は故障しています。誰かがこれを説明できますか?

ありがとう

4

1 に答える 1

1

問題は、パイプへの書き込み方法ですlondonecho "$message" > $madrid_pipe これは、パイプを開いたままにする他のエンドポイントで行うこととは異なり、書き込みごとにパイプを開いたり閉じたりします。これにより、競合状態が発生します。パイプが閉じているときに読み取りを試みた場合、berlinまたは読み取りを試みた場合、読み取りはデータを返しません。以下を参照してください。madridman 7 pipe

パイプの書き込み終了を参照するすべてのファイル記述子が閉じられている場合、パイプからread(2)を試行すると、ファイルの終わりが表示されます(read(2)は0を返します)。

解決策は十分に単純です。これをあなたがしたように処理するかlondon、パイプを開いたままにしておくようにしてください。

于 2012-12-24T15:52:51.230 に答える