Làm cách nào để xóa kết nối ổ cắm CLOSE_WAIT


91

Tôi đã viết một chương trình nhỏ tương tác với một máy chủ trên một cổng cụ thể. Chương trình hoạt động tốt, nhưng:

Sau khi chương trình kết thúc đột ngột và kể từ khi kết nối socket đó được hiển thị ở CLOSE_WAITtrạng thái. Nếu tôi cố gắng chạy một chương trình, nó bị treo và tôi phải buộc nó đóng lại, điều này làm tích tụ nhiều CLOSE_WAIT kết nối ổ cắm hơn .

Có cách nào để xóa các kết nối này không?


4
Bạn không thể (và không nên). CLOSE_WAIT là trạng thái được xác định bởi TCP cho các kết nối đang bị đóng để chờ đối tác xác nhận điều này.
vonbrand

1
Xem thêm unix.stackexchange.com/questions/10106/… ... mà tôi sẽ không bỏ phiếu là trùng lặp, vì nó sẽ kết thúc câu hỏi là lạc đề.
derobert

3
@vonbrand Không, không phải đâu, nó hoàn toàn ngược lại. Đây là trạng thái cho một kết nối đã được đóng bởi ngang hàng và đang chờ ứng dụng cục bộ đóng kết thúc.
Marquis of Lorne,

Nếu bạn đang sử dụng Commons HttpClient thì nuxeo.com/blog/… có rất nhiều thông tin liên quan. Từ RFC 2616, Phần 14: Các ứng dụng HTTP / 1.1 không hỗ trợ kết nối liên tục PHẢI bao gồm tùy chọn kết nối "đóng" trong mọi thông báo.
Mayank Ahuja

Câu trả lời:


79

CLOSE_WAITcó nghĩa là chương trình của bạn vẫn đang chạy và chưa đóng socket (và hạt nhân đang đợi nó làm như vậy). Thêm -pvào netstatđể lấy pid, và sau đó giết nó mạnh hơn ( SIGKILLnếu cần). Điều đó sẽ loại bỏ các CLOSE_WAITổ cắm của bạn . Bạn cũng có thể sử dụng psđể tìm pid.

SO_REUSEADDRdành cho máy chủ và TIME_WAITổ cắm, vì vậy không áp dụng ở đây.


2
tốt ... quá trình đóng gói có thể không phải là tốt nhất nếu chương trình đó mở nhiều kết nối, chỉ một số ít trong số đó ở trong "CLOSE_WAIT": trong trường hợp đó, việc giết quá trình có thể hoàn toàn không thể hoặc không phù hợp (chương trình vẫn hoạt động và cung cấp các dịch vụ, với các kết nối khác). Chỉ cần đóng kết nối đang chờ xử lý sẽ thích hợp hơn nhiều. nhưng thực sự thì bản thân nó thường là chương trình không đóng cục bộ kết nối (CLOSE_WAIT có nghĩa là nó đã nhận được 'FIN' từ đầu kia và chương trình chỉ phải đóng kết nối cục bộ). Một báo cáo lỗi có thể phù hợp
Olivier Dulac

40

Theo mô tả của Crist Clark .

CLOSE_WAIT có nghĩa là đầu cục bộ của kết nối đã nhận được FIN từ đầu kia, nhưng Hệ điều hành đang đợi chương trình ở đầu cục bộ thực sự đóng kết nối của nó.

Vấn đề là chương trình của bạn đang chạy trên máy cục bộ không đóng ổ cắm. Nó không phải là một vấn đề điều chỉnh TCP. Một kết nối có thể (và khá chính xác) ở trong CLOSE_WAIT mãi mãi trong khi chương trình giữ kết nối mở.

Sau khi chương trình cục bộ đóng ổ cắm, HĐH có thể gửi FIN đến đầu cuối từ xa để chuyển bạn sang LAST_ACK trong khi bạn chờ ACK của FIN. Sau khi nhận được, kết nối sẽ hoàn tất và rơi khỏi bảng kết nối (nếu điểm kết thúc của bạn ở CLOSE_WAIT, bạn không kết thúc ở trạng thái TIME_WAIT).


4
làm thế nào để đóng ổ cắm ??
Divyang Shah

1
Bạn đóng tay cầm vào ổ cắm bạn đã mở. Sử dụng close()hoặc closesocket(), tùy thuộc vào nền tảng bạn đang sử dụng.
Remy Lebeau

8

Tôi cũng gặp vấn đề tương tự với máy chủ Tomcat mới nhất (7.0.40). Nó không phản hồi một lần trong một vài ngày.

Để xem các kết nối đang mở, bạn có thể sử dụng:

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

Như đã đề cập trong bài đăng này , bạn có thể sử dụng /proc/sys/net/ipv4/tcp_keepalive_timeđể xem các giá trị. Giá trị dường như tính bằng giây và mặc định là 7200 (tức là 2 giờ).

Để thay đổi chúng, bạn cần chỉnh sửa /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
câu trả lời là khó hiểu. bạn cho biết trạng thái không phản hồi đã biến mất trong vài ngày .. nhưng sau đó bạn cũng cố gắng đặt thời gian duy trì hoạt động chỉ 120 giây. ngay cả với giá trị mặc định (7200 giây), nó sẽ không kéo dài trong vài ngày, phải không?
fanchyna

8

Mặc dù quá nhiều kết nối CLOSE_WAIT có nghĩa là mã của bạn đã xảy ra lỗi trong lần đầu tiên và điều này được chấp nhận là không tốt.

Bạn có thể muốn xem: https://github.com/rghose/kill-close-wait-connections

Những gì tập lệnh này thực hiện là gửi ACK mà kết nối đang chờ đợi.

Đây là những gì làm việc cho tôi.


bạn gửi hành động đến ổ cắm chờ đóng. với không hoạt động .. nếu hoạt động, tại sao?
Chinaxing

Tôi đoán, hệ điều hành đã gửi FIN đến máy chủ từ xa. Máy chủ từ xa có thể không thể trả lời bằng ACK mà ổ cắm đang mong đợi.
ảo ảnh

vâng, đúng vậy (từ mã nhân). nhưng mình cũng nghi ngờ về SEQ của gói tin bạn gửi là "10", kernel không kiểm tra được à?
Chinaxing

Chắc là không. Tôi nghĩ rằng tôi đã thử với nhiều con số ngẫu nhiên, và chúng dường như hoạt động.
ảo ảnh

3

Cần lưu ý rằng Socketcá thể trong cả máy khách và máy chủ cần phải gọi rõ ràng close(). Nếu chỉ một trong các đầu cuối cũng gọi ra close()thì ổ cắm sẽ vẫn ở trạng thái CLOSE_WAIT.


3

Bạn có thể buộc phải đóng các socket bằng sslệnh; các sslệnh là một công cụ dùng để đổ thống kê ổ cắm và hiển thị thông tin trong thời trang tương tự (mặc dù đơn giản hơn và nhanh hơn) để netstat.

Để loại bỏ bất kỳ ổ cắm nào ở trạng thái CLOSE_WAIT, hãy chạy cái này (dưới dạng root)

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

1

Cũng cần lưu ý rằng nếu chương trình của bạn sinh ra một quy trình mới, quy trình đó có thể kế thừa tất cả các chốt đã mở của bạn. Ngay cả sau khi chương trình của riêng bạn bị tắc nghẽn, những tay cầm kế thừa đó vẫn có thể tồn tại thông qua quá trình trẻ mồ côi. Và chúng không nhất thiết phải hiển thị hoàn toàn giống nhau trong netstat. Nhưng tất cả đều giống nhau, socket sẽ treo lơ lửng trong CLOSE_WAIT trong khi tiến trình con này vẫn còn.

Tôi gặp trường hợp đang chạy ADB. Bản thân ADB tạo ra một quy trình máy chủ nếu nó chưa chạy. Điều này kế thừa tất cả các tay cầm của tôi ban đầu, nhưng không hiển thị là sở hữu bất kỳ cái nào trong số chúng khi tôi đang điều tra (điều này cũng đúng cho cả macOS và Windows - không chắc chắn về Linux).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.