`TIME_WAIT` ฝั่งเซิร์ฟเวอร์ทำงานอย่างไร


11

ฉันรู้ว่ามีคำถาม SE ค่อนข้างน้อยเกี่ยวกับเรื่องนี้และฉันเชื่อว่าฉันอ่านมากเท่าที่มันสำคัญก่อนที่จะมาถึงจุดนี้

โดย "ฝั่งเซิร์ฟเวอร์TIME_WAIT" ฉันหมายถึงสถานะของคู่ซ็อกเก็ตฝั่งเซิร์ฟเวอร์ที่มีการปิด () เริ่มต้นที่ฝั่งเซิร์ฟเวอร์

ฉันมักจะเห็นข้อความเหล่านี้ที่ขัดแย้งกับฉัน:

  1. ฝั่งเซิร์ฟเวอร์TIME_WAITไม่เป็นอันตราย
  2. คุณควรออกแบบแอปเครือข่ายของคุณเพื่อให้ไคลเอนต์เริ่มต้นปิด () ดังนั้นให้ลูกค้ารับ TIME_WAIT

เหตุผลที่ฉันพบข้อขัดแย้งนี้เป็นเพราะTIME_WAITในไคลเอนต์อาจมีปัญหา - ลูกค้าสามารถเรียกใช้จากพอร์ตที่มีอยู่ดังนั้นในสาระสำคัญข้างต้นจะแนะนำให้ย้ายภาระของTIME_WAITไปยังฝั่งไคลเอ็นต์ซึ่งอาจเป็นปัญหาจาก ฝั่งเซิร์ฟเวอร์ที่ไม่มีปัญหา

TIME_WAITแน่นอนว่าลูกค้าฝั่งนั้นมีปัญหาเฉพาะกรณีใช้งานในจำนวนที่ จำกัด โซลูชันไคลเอนต์เซิร์ฟเวอร์ส่วนใหญ่จะเกี่ยวข้องกับเซิร์ฟเวอร์เดียวและไคลเอนต์จำนวนมากลูกค้ามักจะไม่จัดการกับการเชื่อมต่อในปริมาณมากพอที่จะเป็นปัญหาและแม้ว่าพวกเขาจะทำมีคำแนะนำจำนวนมากให้ "sanely" ( เมื่อเทียบSO_LINGERกับการหมดเวลา 0 หรือยุ่งกับ tcp_tw sysctls) ต่อสู้ฝั่งไคลเอ็นต์TIME_WAITโดยหลีกเลี่ยงการสร้างการเชื่อมต่อมากเกินไปเร็วเกินไป แต่นั่นไม่ได้เป็นไปได้เสมอตัวอย่างเช่นคลาสของแอปพลิเคชันเช่น:

  • ระบบตรวจสอบ
  • เครื่องกำเนิดไฟฟ้าโหลด
  • ผู้รับมอบฉันทะ

ในอีกด้านฉันไม่เข้าใจด้วยซ้ำว่าฝั่งเซิร์ฟเวอร์TIME_WAITมีประโยชน์อย่างไร เหตุผลTIME_WAITก็คือแม้จะมีเพราะมันช่วยป้องกันการฉีดTCPชิ้นส่วนเก่าค้างในกระแสที่พวกเขาไม่ได้เป็นของอีกต่อไป สำหรับฝั่งไคลเอ็นต์TIME_WAITมันสามารถทำได้โดยเพียงทำให้เป็นไปไม่ได้ที่จะสร้างการเชื่อมต่อกับip:portคู่เดียวกันกับที่การเชื่อมต่อเก่านี้อาจมี (คู่ที่ใช้ถูกล็อคโดยTIME_WAIT) แต่สำหรับฝั่งเซิร์ฟเวอร์สิ่งนี้ไม่สามารถป้องกันได้เนื่องจากที่อยู่ในท้องถิ่นจะมีพอร์ตที่ยอมรับและจะเหมือนกันเสมอและเซิร์ฟเวอร์ไม่สามารถ (AFAIK ฉันมีหลักฐานเชิงประจักษ์เท่านั้น) ปฏิเสธการเชื่อมต่อเพียงเพราะ เพียร์ที่เข้ามาจะสร้างคู่ที่อยู่เดียวกันที่มีอยู่แล้วในตารางซ็อกเก็ต

ฉันเขียนโปรแกรมที่แสดงว่าเซิร์ฟเวอร์จะไม่สนใจ TIME-WAIT ยิ่งกว่านั้นเนื่องจากการทดสอบเสร็จสิ้นใน 127.0.0.1 เคอร์เนลจะต้องมีบิตพิเศษที่จะบอกว่าเป็นฝั่งเซิร์ฟเวอร์หรือฝั่งไคลเอ็นต์ (เนื่องจากมิฉะนั้น tuple จะเหมือนกัน)

แหล่งที่มา: http://pastebin.com/5PWjkjEfทดสอบบน Fedora 22 แล้วค่าปริยายสุทธิ

$ gcc -o rtest rtest.c -lpthread
$ ./rtest 44400 s # will do server-side close
Will initiate server close
... iterates ~20 times successfully
^C
$ ss -a|grep 44400
tcp    TIME-WAIT  0      0            127.0.0.1:44400         127.0.0.1:44401   
$ ./rtest 44500 c # will do client-side close
Will initiate client close
... runs once and then
connecting...
connect: Cannot assign requested address

ดังนั้นสำหรับฝั่งเซิร์ฟเวอร์การTIME_WAITเชื่อมต่อในคู่พอร์ตเดียวกันที่แน่นอนสามารถสร้างขึ้นใหม่ได้ทันทีและสำเร็จและสำหรับฝั่งไคลเอ็นต์TIME-WAITในการทำซ้ำครั้งที่สองconnect()ล้มเหลวอย่างถูกต้อง

เพื่อสรุปคำถามคือสองเท่า:

  • ฝั่งเซิร์ฟเวอร์TIME_WAITไม่ได้ทำอะไรจริง ๆ และเหลือเพียงเพราะวิธีRFCนี้ใช่ไหม?
  • เหตุผลที่ลูกค้าแนะนำให้เริ่มต้นปิด () เพราะเซิร์ฟเวอร์TIME_WAITไม่มีประโยชน์หรือไม่?

คุณจะไม่ใช้งานพอร์ตจนหมดเว้นแต่ว่าคุณจะมีลูกค้าเพียง 1 รายเท่านั้น คุณมีพอร์ต 65535 สำหรับการรวมกันของไคลเอนต์ / เซิร์ฟเวอร์ IP การเชื่อมต่อจาก 1.2.3.4:1111 นั้นแตกต่างจาก 4.3.2.1:1111 ใช้หน่วยความจำเพียงไม่กี่ไบต์สำหรับการเชื่อมต่อแต่ละTIME_WAITครั้ง
Marki555

คำตอบ:


1

ในฝั่งเซิร์ฟเวอร์TCPข้อกำหนดที่นี่หมายถึงโฮสต์ที่มีซ็อกเก็ตในสถานะ LISTEN

RFC1122อนุญาตให้ซ็อกเก็ตอยู่ในสถานะ TIME-WAIT เพื่อยอมรับการเชื่อมต่อใหม่ที่มีเงื่อนไขบางประการ

        When a connection is closed actively, it MUST linger in
        TIME-WAIT state for a time 2xMSL (Maximum Segment Lifetime).
        However, it MAY accept a new SYN from the remote TCP to
        reopen the connection directly from TIME-WAIT state, if it:

สำหรับรายละเอียดที่แน่นอนเกี่ยวกับเงื่อนไขโปรดดูRFC1122 ฉันคาดว่าจะต้องมีการจับคู่แบบพาสซีฟ OPEN บนซ็อกเก็ต (ซ็อกเก็ตในสถานะ LISTEN)

ใช้งานเปิด (ด้านลูกค้าโทร Connect) ไม่ได้มีข้อยกเว้นดังกล่าวและต้องให้ความผิดพลาดเมื่อซ็อกเก็ตที่อยู่ในระยะเวลาที่รอตามRFC793

ฉันเดาสำหรับคำแนะนำเกี่ยวกับลูกค้า (ในแง่ TCP โฮสต์ดำเนินการเปิด OPEN เช่นการเชื่อมต่อ) เริ่มต้นใกล้เคียงกับของคุณมากว่าในกรณีทั่วไปมันกระจายซ็อกเก็ต TIME-WAIT บนโฮสต์มากขึ้นที่มีทรัพยากรมากมายสำหรับ ซ็อกเก็ต ในกรณีที่ลูกค้าทั่วไปไม่ส่ง SYN ที่จะใช้ซ็อกเก็ต TIME-WAIT บนเซิร์ฟเวอร์ ฉันยอมรับว่าการใช้คำแนะนำดังกล่าวยังคงขึ้นอยู่กับกรณีการใช้งาน


0

นี่อาจเป็นตัวอย่างที่ชัดเจนที่สุดของสิ่งที่ TIME-WAIT ทำจริงและที่สำคัญกว่านั้นคือเหตุใดจึงสำคัญ นอกจากนี้ยังอธิบายถึงสาเหตุที่ต้องหลีกเลี่ยงเคล็ดลับ 'ผู้เชี่ยวชาญ' บนเครื่อง Linux เพื่อ 'ลด' TIME-WAIT's


ยังคงไม่ได้อธิบายสิ่งที่เกิดขึ้นเมื่อไคลเอ็นต์> การเชื่อมต่อเซิร์ฟเวอร์ที่มีการริเริ่มและเซิร์ฟเวอร์มีคู่ที่ล็อคออกใน TIME_WAIT
Pawel Veselov

โปรดดูstackoverflow.com/questions/1490196/… - คำตอบคือสิ่งที่คุณกำลังมองหา
Khushil

0

เซสชัน tcp ถูกระบุโดย tupple (sourceIP, sourcePort, destIP, destPort) ดังนั้น TIME_WAIT จึงใช้งานได้กับทุกการเชื่อมต่อ tcp

เกี่ยวกับด้านปิดในบางสถานการณ์การปิดจากฝั่งไคลเอ็นต์สามารถลดซ็อกเก็ต TIME_WAIT บนเซิร์ฟเวอร์จึงลดหน่วยความจำเล็กน้อย ในกรณีที่ซ็อกเก็ตพื้นที่สามารถหมด (เนื่องจากการสูญเสียพอร์ตชั่วคราว) (เช่นลูกค้าโลภที่มีการเชื่อมต่อจำนวนมากไปยังเซิร์ฟเวอร์เดียวกัน) ปัญหานี้ควรได้รับการแก้ไขในด้านใดด้านหนึ่ง


กรุณาอธิบาย; เมื่อคุณถามว่า TW ฝั่งเซิร์ฟเวอร์ทำอะไรหรือไม่คุณสงสัยว่าการเชื่อมต่อเดียวกันสามารถนำมาใช้ซ้ำได้หรือไม่ในช่วงเวลา TW คำตอบคือไม่ใช่เพราะการเชื่อมต่อตามที่กำหนดโดย tupple เกิดขึ้นในตาราง tcp ของเซิร์ฟเวอร์ หากลูกค้าพยายามที่จะเปิดการเชื่อมต่อเดียวกันในไม่ช้ามันจะได้รับ RST ปฏิเสธการเชื่อมต่อ tcp ได้อย่างมีประสิทธิภาพ อย่างไรก็ตามบทความจาก Khushil มีความหมายมาก
basos

ฉันขอโทษจริง ๆ คำตอบของคุณตอบคำถามฉันอ่านผิดและเพิกถอนความคิดเห็นของฉัน อย่างไรก็ตามดูเหมือนว่าจะไม่ถูกต้องเนื่องจากฉันมีรหัสที่ดูเหมือนจะพิสูจน์ว่าไม่มีการป้องกันจากฝั่งเซิร์ฟเวอร์TIME_WAIT(ฉันอัปเดตคำถามด้วยข้อมูลนั้น) @ การอ้างอิงของ Khushil ไม่ครอบคลุมTIME_WAITกรณีฝั่งเซิร์ฟเวอร์โดยละเอียด
Pawel Veselov

-2

คุณไม่สามารถมั่นใจได้กับโพรโทคอลที่ไม่น่าเชื่อถือว่าคุณได้รับข้อความล่าสุดจากอุปกรณ์เพียร์ของคุณดังนั้นมันจึงเป็นอันตรายที่จะคิดว่าเพียร์ของคุณได้วางสายโทรศัพท์ไว้ในทันที มันเป็นข้อเสียที่สำคัญของโปรโตคอล TCP ที่มีเพียง 65000 พอร์ตเท่านั้นที่สามารถเปิดพร้อมกันได้ แต่วิธีที่จะเอาชนะสิ่งนี้ก็คือย้ายไปที่เซิร์ฟเวอร์ฟาร์มซึ่งปรับขนาดได้ดีกว่ากับโหลดมากกว่าการรีไซเคิลหมายเลขพอร์ตอย่างรวดเร็ว ในตอนท้ายไคลเอนต์มีความเป็นไปได้สูงมากที่คุณจะหมดพอร์ตหากเป็นเวิร์กสเตชันพื้นฐาน


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