經過一些100年的組合後,我導致下面的代碼使用一個進程作爲服務器和管道來讀取來自客戶端的響應,我稱之爲'london'函數,它的管道'london_pipe'(我非常不確定要調用我的管道'倫敦'也是因爲命名衝突?)。 下面有兩個客戶端,每個客戶端都與自己的管道通信,並與服務器通信以讀取數據。我遵循相同的命名約定,使用讀取的函數名稱命名管道。所以,「柏林」是「berlin_pipe」等閱讀2個進程之間使用的命名管道(第3號)有什麼問題?
整體結構採用鋼管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 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:>
很明顯,'馬德里'沒有讀過空字符串以及來自'倫敦'的具有循環編號86等的消息,這些消息已經被先前的空讀取所推動,並且現在無序。 有人可以解釋這一點嗎?
感謝
謝謝,我認爲有些事情現在已經闡明。最重要的是重定向字符關閉後的管道!我注意到的一件事是,服務器可以在進入其循環之前啓動帶有作業的客戶端,並且在進入之後立即開始捕捉客戶端的回聲而不丟失數據。我認爲,升級作業和進入客戶端循環之間的時間可以在服務器的管道中寫入災難結果,因爲循環不僅僅是打開了,但幸運的是數據在那裏!最後一件事是,'倫敦'怎麼打開它寫入的管道?無法想象它! – centurian
就像柏林和馬德里那樣。只需使用'exec',然後寫入循環中的文件描述符。 – Jester