Bash รอความสำเร็จในการ ping


10

ฉันกำลังเขียนสคริปต์ที่รีบูตเซิร์ฟเวอร์ต่าง ๆ หลังจากรีบูตฉันต้องการ "รอ" จนกว่าเซิร์ฟเวอร์ทั้งหมดจะกลับมาออนไลน์ (เพื่อให้สิ่งที่เรียบง่ายฉันกำหนดให้ฉันออนไลน์ = pingable)

ดังนั้นสำหรับแต่ละเซิร์ฟเวอร์ฉันทำ

ServerXY_W=1
echo -n "waiting for ServerXY ..."
while (($ServerXY_W == 1))
do
   if ping -c 1 -w 0.2 192.168.123.123 &> /dev/null
   then
      echo "ServerXY is back online!"
      ServerXY_W=0
   else
      echo -n "."
   fi
done

สิ่งที่ฉันคาดหวัง (และชอบ) จะเป็นเช่นเอาท์พุท

waiting for ServerXY .................
ServerXY is back online!

จุดที่ .... จะปรากฏทีละหนึ่ง

แต่สิ่งที่เกิดขึ้นจริงคือก่อนมีเพียง

waiting for ServerXY ...

ชั่วขณะหนึ่งและเมื่อเซิร์ฟเวอร์กลับมาฉันจะได้รับจุดสุดท้ายและบรรทัดสุดท้ายเหมือน

waiting for ServerXY ....
ServerXY is back online!

เหตุใดขณะที่ลูปดำเนินการสองครั้งเหมือนครั้งเดียวโดย ping ล้มเหลวและอีกครั้งเมื่อสำเร็จ ping ฉันต้องเปลี่ยนอะไรเพื่อให้ได้จุดเพิ่มเข้ามาในขณะที่ลูป

ฉันทำการทดสอบด้วย IP ที่ไม่มีอยู่จริง แต่มันติดอยู่กับ

waiting for NonExistentServer...

และไม่สิ้นสุดแน่นอน แต่คำถามเดียวกันทำไมไม่........เพิ่มเข้าไป?


ทำงานได้ดีสำหรับฉัน ... : /
Ravexina

คำตอบ:


9

ปัญหา

-w 0.2ปัญหาคือว่าคุณได้ตั้ง เมื่อค่าต่ำกว่า 1 ค่ากำหนด ( -w) และหมดเวลา ( -W) จะถูกละเว้น เรื่องนี้ถูกกล่าวถึงก่อนหน้านี้ในคำถามนี้ เมื่อคุณใช้-w 1สคริปต์ของคุณ (ซึ่งฉันปรับเปลี่ยนเล็กน้อยเพื่อลบบิตไร้ประโยชน์) ทำงานอย่างถูกต้อง:

$ ./ping_server.sh                                                 
waiting for ServerXY ....................
Server is back online

$ cat ./ping_server.sh
#!/bin/bash
printf "%s" "waiting for ServerXY ..."
while ! ping -c 1 -n -w 1 147.153.237.192 &> /dev/null
do
    printf "%c" "."
done
printf "\n%s\n"  "Server is back online"

สารละลาย

-w 1วิธีการแก้ปัญหาที่ชัดเจนคือการใช้งาน หากคุณตั้งใจจะใช้ค่าต่ำกว่า 1 วินาทีtimeoutคำสั่งควรจะดีกว่า:

$ timeout 0.2 ping -c 1 147.153.237.192                            
PING 147.153.237.192 (147.153.237.192) 56(84) bytes of data.
64 bytes from 147.153.237.192: icmp_seq=1 ttl=124 time=2.61 ms

--- 147.153.237.192 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.612/2.612/2.612/0.000 ms

ใช้กับ!โอเปอเรเตอร์ในลูปอีกครั้ง:

#!/bin/bash
printf "%s" "waiting for ServerXY ..."
while ! timeout 0.2 ping -c 1 -n 147.153.237.192 &> /dev/null
do
    printf "%c" "."
done
printf "\n%s\n"  "Server is back online"

แน่นอนว่าสิ่งที่ตรงกันข้ามสามารถนำไปใช้กับการแสดงข้อความเฉพาะเมื่อเซิร์ฟเวอร์ขึ้นและรายงานเมื่อเซิร์ฟเวอร์ล่มตัวอย่างเช่น:

$ while ping -q -c 1 172.16.127.2 >/dev/null ; do sleep 1; done ; echo "Server stopped responding"
Server stopped responding

อย่างไรก็ตามโปรดทราบว่านี่ไม่สมบูรณ์แบบ:

  • เรากำลังส่งข้อมูลเพียง 1 แพ็คเก็ตทุกวินาที แบนด์วิดธ์ต่ำ, การเชื่อมต่อที่ไม่ดี, ฮาร์ดแวร์ที่ไม่ดีในระหว่างเซิร์ฟเวอร์และไคลเอนต์ที่ส่งเสียงปิ๊งเซิร์ฟเวอร์จะทริกเกอร์ลูปเพื่อออก

  • เราพึ่งพาการส่ง Ping ซึ่งกำลังใช้ ICMP echo ไฟร์วอลล์หรือแม้กระทั่งเซิร์ฟเวอร์แต่ละเครื่องจะปิดกั้นการตอบสนองต่อ ping / ICMP echo คุณสามารถใช้ncของncat(ซึ่งเป็นรุ่นปรับปรุงของnc) สิ่งที่ชอบในลูปด้านบนจะทำงานได้ดีแทนping:

    nc -w5 -z 172.16.127.2 80

    สิ่งนี้จะเชื่อมต่อกับเซิร์ฟเวอร์บน 172.16.127.2 ที่พอร์ต 80 -zคือการหลีกเลี่ยง I / O - เพียงแค่เชื่อมต่อและยกเลิกการเชื่อมต่อ -wคือการรอ 5 วินาทีก่อนการรายงานการเชื่อมต่อล้มเหลว ของหลักสูตรนี้ค่อนข้างดีเมื่อคุณมีเซิร์ฟเวอร์ภายใต้การควบคุมของคุณและคุณรู้ว่าพอร์ต 80 เปิดอยู่ UPD สามารถใช้งานได้ดี แต่ถ้ามีไฟร์วอลล์อยู่อาจแนะนำให้ใช้ TCP

    ประโยชน์ที่ซ่อนอยู่ที่นี่คือถ้าคุณมีบริการบางอย่างทำงานบนพอร์ตเฉพาะ (เช่น HTTP บนพอร์ต 80 หรือ RTSP บน 554) ความล้มเหลวในการเชื่อมต่อกับพอร์ตอาจทำหน้าที่เป็นตัวบ่งชี้บริการของคุณต้องการเริ่มต้นใหม่

  • แน่นอนncและpingอาจเป็นสแปมเล็กน้อย วิธีที่ดีกว่าคือการให้เซิร์ฟเวอร์เช็คอินกับเซิร์ฟเวอร์ส่วนกลางอื่นส่งรายงานเป็นระยะบางทีในแต่ละชั่วโมง ด้วยวิธีนี้หากเซิร์ฟเวอร์ของคุณพลาด "punch time" คุณสามารถสร้างข้อผิดพลาดได้ วิธีที่ดีกว่าคือใช้บริการเช่น Nagios ซึ่งทำเช่นนั้น แต่ ณ จุดนี้เรากำลังเข้าสู่อาณาจักรแห่งการคำนวณระดับองค์กรด้วยเซิร์ฟเวอร์หลายตัว หากคุณมีอะไรที่เหมือนกับราสเบอร์รี่ Pi อยู่ที่บ้านคุณอาจไม่ต้องการอะไรที่ซับซ้อน


สวัสดีขอบคุณมากสำหรับการล้างสิ่งนั้น -w! มีวิธีที่แตกต่างจากที่ทำในสภาพลูปหรือไม่? มันสมบูรณ์แบบสำหรับการรอเซิร์ฟเวอร์หนึ่งเครื่อง แต่อย่างที่กล่าวไปแล้วฉันกำลังรอเซิร์ฟเวอร์หลายเครื่องในภายหลังฉันจะทำสิ่งwhile (( $ServerA_W==1 || $ServerB_W==1 || .....))ที่เก็บไว้เมื่อเซิร์ฟเวอร์ทุกเครื่องกลับมา
derHugo

หลังจากเช่นเซิร์ฟเวอร์หนึ่งจะกลับรอให้คนอื่น ๆ ที่ผมไม่ต้องการที่จะ ping ที่หนึ่งที่จะกลับมาแล้ว;)
derHugo

ฉันขอแนะนำให้เขียนว่าเป็นฟังก์ชั่นและเปิดตัวอย่างของแต่ละฟังก์ชั่นที่มีที่อยู่ IP เป็นอาร์กิวเมนต์ในพื้นหลัง แต่ฉันขอแนะนำไม่ให้พิมพ์จุดเพียงให้แต่ละข้อความพิมพ์ฟังก์ชั่นเมื่อเซิร์ฟเวอร์เกิดขึ้น แจ้งให้เราทราบหากคุณต้องการให้ฉันเขียนตัวอย่างของฟังก์ชั่นดังกล่าว
Sergiy Kolodyazhnyy

1
@ โจแอนใช่มันเป็นไปได้ ฉันสามารถอัปเดตคำตอบของฉันในวันนี้หรือพรุ่งนี้ โดยส่วนตัวฉันจะไม่ทำการปิงเซิร์ฟเวอร์อย่างต่อเนื่องเพราะมันเป็นสแปมน้อย ๆ
Sergiy Kolodyazhnyy

1
@Joanne ดูการอัพเดตของฉันในคำตอบ แจ้งให้เราทราบว่าสิ่งนั้นช่วยได้หรือมีคำถามอื่น ๆ อีกหรือไม่
Sergiy Kolodyazhnyy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.