ฉันจะลบการเชื่อมต่อซ็อกเก็ต CLOSE_WAIT ได้อย่างไร


92

ฉันได้เขียนโปรแกรมขนาดเล็กที่โต้ตอบกับเซิร์ฟเวอร์บนพอร์ตเฉพาะ โปรแกรมทำงานได้ดี แต่:

เมื่อโปรแกรมสิ้นสุดลงโดยไม่คาดคิดและนับตั้งแต่การเชื่อมต่อซ็อกเก็ตนั้นแสดงอยู่ในCLOSE_WAITสถานะ ถ้าฉันพยายามเรียกใช้โปรแกรมมันแฮงค์และฉันต้องบังคับให้ปิดซึ่งจะสะสมการเชื่อมต่อซ็อกเก็ตมาก ยิ่งขึ้นCLOSE_WAIT

มีวิธีล้างการเชื่อมต่อเหล่านี้หรือไม่?


4
คุณทำไม่ได้ (และไม่ควร) CLOSE_WAIT เป็นสถานะที่กำหนดโดย TCP สำหรับการเชื่อมต่อที่ถูกปิดเพื่อรอให้คู่สัญญารับทราบสิ่งนี้
vonbrand

1
โปรดดูunix.stackexchange.com/questions/10106/… ... ซึ่งฉันจะไม่โหวตว่าซ้ำกันเพราะมันจะปิดคำถามเป็นนอกประเด็น
derobert

4
@vonbrand ไม่มันไม่ตรงกันข้าม เป็นสถานะสำหรับการเชื่อมต่อที่เพียร์ปิดไปแล้วและกำลังรอให้แอปพลิเคชันภายในเครื่องปิดการสิ้นสุด
user207421

หากคุณใช้ Commons HttpClient แล้วnuxeo.com/blog/…มีข้อมูลที่เกี่ยวข้องมากมาย จาก RFC 2616 ส่วนที่ 14: แอปพลิเคชัน HTTP / 1.1 ที่ไม่รองรับการเชื่อมต่อแบบถาวรจะต้องมีตัวเลือกการเชื่อมต่อ "ปิด" ในทุกข้อความ
Mayank Ahuja

คำตอบ:


80

CLOSE_WAITหมายความว่าโปรแกรมของคุณยังทำงานอยู่และยังไม่ได้ปิดซ็อกเก็ต (และเคอร์เนลกำลังรอให้ทำเช่นนั้น) เพิ่ม-pเพื่อnetstatรับ pid แล้วฆ่ามันอย่างแรง ( SIGKILLถ้าจำเป็น) ที่ควรกำจัดCLOSE_WAITซ็อกเก็ตของคุณ คุณยังสามารถใช้psเพื่อค้นหา pid

SO_REUSEADDRมีไว้สำหรับเซิร์ฟเวอร์และTIME_WAITซ็อกเก็ตดังนั้นจึงไม่ใช้ที่นี่


2
ดี ... การฆ่ากระบวนการอาจไม่ดีที่สุดหากโปรแกรมนั้นเปิดการเชื่อมต่อจำนวนมากมีเพียงไม่กี่คนที่อยู่ใน "CLOSE_WAIT": ในกรณีนี้การฆ่ากระบวนการอาจเป็นไปไม่ได้ทั้งหมดหรือไม่เหมาะสม (โปรแกรมยังคงทำงานและ ให้บริการกับการเชื่อมต่ออื่น ๆ ) เพียงแค่ปิดการเชื่อมต่อที่รอดำเนินการจะเหมาะสมกว่ามาก แต่โดยปกติแล้วจะเป็นโปรแกรมเองซึ่งไม่ได้ปิดการเชื่อมต่อภายในเครื่อง (CLOSE_WAIT หมายถึงได้รับ 'FIN' จากปลายอีกด้านหนึ่งและโปรแกรมจะต้องปิดการเชื่อมต่อในเครื่อง รายงานข้อผิดพลาดอาจเหมาะสม
Olivier Dulac

41

ตามที่คริสคลาร์กอธิบาย

CLOSE_WAIT หมายถึงการสิ้นสุดการเชื่อมต่อภายในเครื่องได้รับ FIN จากปลายอีกด้านหนึ่ง แต่ระบบปฏิบัติการกำลังรอให้โปรแกรมที่จุดสิ้นสุดภายในเครื่องเพื่อปิดการเชื่อมต่อจริง

ปัญหาคือโปรแกรมของคุณทำงานบนเครื่องโลคัลไม่ได้ปิดซ็อกเก็ต ไม่ใช่ปัญหาการปรับ TCP การเชื่อมต่อสามารถ (และค่อนข้างถูกต้อง) อยู่ใน CLOSE_WAIT ตลอดไปในขณะที่โปรแกรมเปิดการเชื่อมต่อไว้

เมื่อโปรแกรมโลคัลปิดซ็อกเก็ตระบบปฏิบัติการจะส่ง FIN ไปยังจุดสิ้นสุดระยะไกลซึ่งจะเปลี่ยนคุณเป็น LAST_ACK ในขณะที่คุณรอ ACK ของ FIN เมื่อได้รับแล้วการเชื่อมต่อจะเสร็จสิ้นและออกจากตารางการเชื่อมต่อ (หากจุดสิ้นสุดของคุณอยู่ใน CLOSE_WAIT คุณจะไม่สิ้นสุดในสถานะ TIME_WAIT)


4
ปิดเบ้ายังไง ??
Divyang Shah

1
คุณปิดที่จับที่คุณต้องเข้ากับซ็อกเก็ตที่คุณเปิด ใช้close()หรือclosesocket()ขึ้นอยู่กับแพลตฟอร์มที่คุณใช้
Remy Lebeau

8

ฉันกำลังประสบปัญหาเดียวกันกับเซิร์ฟเวอร์ Tomcat ล่าสุด (7.0.40) มันไม่ตอบสนองหนึ่งครั้งเป็นเวลาสองสามวัน

หากต้องการดูการเชื่อมต่อแบบเปิดคุณสามารถใช้:

sudo netstat -tonp | grep jsvc | grep --regexp="127.0.0.1:443" --regexp="127.0.0.1:80" | grep CLOSE_WAIT

ดังที่ได้กล่าวไว้ในโพสต์นี้คุณอาจใช้/proc/sys/net/ipv4/tcp_keepalive_timeเพื่อดูค่าต่างๆ ค่านี้ดูเหมือนจะเป็นวินาทีและมีค่าเริ่มต้นเป็น 7200 (เช่น 2 ชั่วโมง)

คุณต้องแก้ไขจึงจะ/etc/sysctl.confเปลี่ยนได้

Open/create `/etc/sysctl.conf`
Add `net.ipv4.tcp_keepalive_time = 120` and save the file
Invoke `sysctl -p /etc/sysctl.conf`
Verify using `cat /proc/sys/net/ipv4/tcp_keepalive_time`

4
คำตอบนั้นสับสน คุณบอกว่าสถานะที่ไม่ตอบสนองนั้นหายไปหลายวันแล้ว .. แต่คุณก็พยายามตั้งเวลาให้มีชีวิตอยู่เพียง 120 วินาที แม้จะมีค่าเริ่มต้น (7200 วินาที) ก็ไม่ควรอยู่นานหลายวันใช่ไหม?
fanchyna

8

แม้ว่าการเชื่อมต่อ CLOSE_WAIT มากเกินไปหมายความว่ามีบางอย่างผิดปกติกับโค้ดของคุณในครั้งแรกและยอมรับว่านี่ไม่ใช่แนวทางปฏิบัติที่ดี

คุณอาจต้องการตรวจสอบ: https://github.com/rghose/kill-close-wait-connections

สิ่งที่สคริปต์นี้ทำคือส่ง ACK ซึ่งกำลังรอการเชื่อมต่ออยู่

นี่คือสิ่งที่ได้ผลสำหรับฉัน


คุณส่งการกระทำไปยังซ็อกเก็ตรอปิด กับไม่ทำงาน .. ถ้าได้ผลทำไม?
Chinaxing

ฉันเดาว่าระบบปฏิบัติการได้ส่ง FIN ไปยังโฮสต์ระยะไกลแล้ว โฮสต์ระยะไกลอาจไม่สามารถตอบกลับด้วย ACK ที่ซ็อกเก็ตคาดหวัง
ภาพลวงตา

ใช่ถูกต้อง (จากรหัสเคอร์เนล) แต่ฉันยังสงสัยเกี่ยวกับ SEQ ของแพ็กเก็ตที่คุณส่งซึ่งเป็น "10" เคอร์เนลไม่ได้ตรวจสอบหรือไม่
Chinaxing

อาจจะไม่. ฉันคิดว่าฉันลองสุ่มตัวเลขหลาย ๆ ตัวแล้วและดูเหมือนว่าจะได้ผล
ภาพลวงตา

5

คุณสามารถบังคับปิดซ็อกเก็ตด้วยssคำสั่ง ssคำสั่งเป็นเครื่องมือที่ใช้ในการถ่ายโอนข้อมูลสถิติซ็อกเก็ตและแสดงข้อมูลในรูปแบบเหมือนกัน (ถึงแม้จะง่ายและเร็วขึ้น) เพื่อ netstat

หากต้องการฆ่าซ็อกเก็ตใด ๆ ในสถานะ CLOSE_WAIT ให้รันสิ่งนี้ (ในฐานะรูท)

$ ss --tcp state CLOSE-WAIT --kill

นั่นน่าจะเป็นคำตอบอันดับต้น ๆ
ทอม

3

มันควรจะกล่าวว่าเช่นในลูกค้าทั้งในและความต้องการของเซิร์ฟเวอร์อย่างชัดเจนวิงวอนSocket close()หากปลายด้านใดด้านหนึ่งเรียกใช้close()ซ็อกเก็ตจะยังคงอยู่ในสถานะ CLOSE_WAIT


1

นอกจากนี้ยังเป็นที่น่าสังเกตว่าหากโปรแกรมของคุณสร้างกระบวนการใหม่กระบวนการนั้นอาจสืบทอดแฮนเดิลที่เปิดอยู่ทั้งหมดของคุณ แม้ว่าโปรแกรมของคุณจะคลัสเตอร์แฮนเดิลที่สืบทอดมาเหล่านั้นก็ยังคงมีชีวิตอยู่ได้ผ่านกระบวนการเด็กกำพร้า และไม่จำเป็นต้องแสดงเหมือนกันใน netstat แต่เหมือนกันทั้งหมดซ็อกเก็ตจะค้างใน CLOSE_WAIT ในขณะที่กระบวนการย่อยนี้ยังมีชีวิตอยู่

ฉันมีกรณีที่ฉันใช้งาน ADB ADB เองสร้างกระบวนการเซิร์ฟเวอร์หากยังไม่ได้ทำงาน สิ่งนี้สืบทอดการจัดการทั้งหมดของฉันในตอนแรก แต่ไม่ได้แสดงว่าเป็นเจ้าของใด ๆ เมื่อฉันกำลังตรวจสอบ (เช่นเดียวกันกับทั้ง macOS และ Windows - ไม่แน่ใจเกี่ยวกับ Linux)

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