CLOSE_WAIT soket bağlantısını nasıl kaldırırım


91

Belirli bir bağlantı noktasındaki bir sunucu ile etkileşim kuran küçük bir program yazdım. Program iyi çalışıyor, ancak:

Program beklenmedik şekilde sona erdiğinde ve o soket bağlantısı durumda gösterildiğinden beri CLOSE_WAIT. Bir programı çalıştırmayı denersem kilitleniyor ve onu kapatmaya zorlamam gerekiyor, bu da daha fazla CLOSE_WAIT soket bağlantısı biriktiriyor .

Bu bağlantıları temizlemenin bir yolu var mı?


4
Yapamazsınız (ve yapmamalısınız). CLOSE_WAIT, karşı tarafın bunu onaylamasını bekleyen, kapatılan bağlantılar için TCP tarafından tanımlanan bir durumdur.
vonbrand

1
Ayrıca bkz. Unix.stackexchange.com/questions/10106/… ... ki bunu tekrar olarak oylamayacağım, çünkü soruyu konu dışı olarak kapatır.
derobert

4
@vonbrand Hayır değil, tam tersi. Eş tarafından zaten kapatılmış olan ve yerel uygulamanın sonunu kapatmasını bekleyen bir bağlantının durumudur.
Marquis of Lorne

Commons HttpClient kullanıyorsanız , nuxeo.com/blog/… birçok ilgili bilgiye sahiptir. RFC 2616, Bölüm 14: Kalıcı bağlantıları desteklemeyen HTTP / 1.1 uygulamaları her mesajda "kapat" bağlantı seçeneğini içermelidir * ZORUNLU *.
Mayank Ahuja

Yanıtlar:


79

CLOSE_WAITprogramınızın hala çalıştığı ve soketi kapatmadığı (ve çekirdeğin bunu yapmasını beklediği) anlamına gelir. Ekle -piçin netstatpid almak ve sonra (daha zorla öldürmek SIGKILLgerekiyorsa). Bu, CLOSE_WAITsoketlerinizden kurtulmalıdır . psPid'i bulmak için de kullanabilirsiniz .

SO_REUSEADDRsunucular ve TIME_WAITsoketler içindir, bu yüzden burada geçerli değildir.


2
peki ... o program çok fazla bağlantı açarsa, süreci çözmek en iyisi olmayabilir, sadece "CLOSE_WAIT" de kalanlardan sadece birkaçı: bu durumda süreci sonlandırmak tamamen imkansız veya uygunsuz olabilir (program hala çalışıyor ve diğer bağlantılarla hizmet sağlar). Sadece bekleyen bağlantıyı kapatmak çok daha uygun olacaktır. ama aslında connectino'yu yerel olarak kapatmayan genellikle programın kendisidir (CLOSE_WAIT, diğer uçtan 'FIN' aldığını ve programın bağlantıyı yerel olarak kapatması gerektiği anlamına gelir). Bir hata raporu uygun olabilir
Olivier Dulac

41

Crist Clark tarafından anlatıldığı gibi .

CLOSE_WAIT, bağlantının yerel ucunun diğer uçtan bir FIN aldığı, ancak işletim sisteminin yerel uçta programın bağlantısını gerçekten kapatmasını beklediği anlamına gelir.

Sorun, yerel makinede çalışan programınızın soketi kapatmamasıdır. Bu bir TCP ayarlama sorunu değildir. Program bağlantıyı açık tutarken bir bağlantı CLOSE_WAIT'de sonsuza kadar kalabilir (ve oldukça doğru bir şekilde).

Yerel program soketi kapattıktan sonra, siz FIN'in ACK'sını beklerken, işletim sistemi FIN'i uzak uca gönderebilir ve bu da sizi LAST_ACK'e geçirir. O alındıktan sonra, bağlantı bitti ve (bitiş CLOSE_WAIT içinde olup olmadığını do bağlantı tablodan damla değil TIME_WAIT durumunda sona).


4
soket nasıl kapatılır?
Divyang Shah

1
Açtığınız sokete sahip olduğunuz kolu kapatırsınız. Kullandığınız platforma bağlı olarak close()veya kullanın closesocket().
Remy Lebeau

8

Aynı sorunu en son Tomcat sunucusuyla (7.0.40) yaşıyorum. Birkaç gün boyunca bir kez yanıt vermiyor.

Açık bağlantıları görmek için şunları kullanabilirsiniz:

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

Bu yazıda belirtildiği gibi /proc/sys/net/ipv4/tcp_keepalive_time, değerleri görüntülemek için kullanabilirsiniz . Değer saniye cinsinden görünüyor ve varsayılan olarak 7200 (yani 2 saat).

Bunları değiştirmek için düzenlemeniz gerekir /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
cevap kafa karıştırıcı. Tepki vermeyen durumların birkaç gündür gittiğini söylediniz .. ama sonra canlı tutma süresini sadece 120 saniyeye ayarlamaya çalışıyorsunuz. varsayılan değerle (7200 sn) bile, birkaç gün sürmemelidir, değil mi?
fanchyna

8

CLOSE_WAIT bağlantılarının çok fazla olması, ilkinde kodunuzda bir sorun olduğu anlamına gelse de, bu iyi bir uygulama olarak kabul edilmemektedir.

Kontrol etmek isteyebilirsiniz: https://github.com/rghose/kill-close-wait-connections

Bu komut dosyasının yaptığı şey, bağlantının beklediği ACK'yı göndermektir.

Bu benim için çalıştı.


kapanış soketine hareket gönderirsiniz. çalışmıyor .. çalışıyorsa, neden?
Chinaxing

Tahmin ediyorum, işletim sistemi FIN'i uzak ana bilgisayara zaten gönderdi. Uzak ana bilgisayar büyük olasılıkla, soketin beklediği ACK ile yanıt veremiyor.
serap

evet, bu doğru (çekirdek kodundan). ama gönderdiğiniz paketin "10" olan SEQ'sinden de şüpheliyim, çekirdek bunu kontrol etmiyor mu?
Chinaxing

Muhtemelen değil. Sanırım birçok rastgele sayı ile denedim ve işe yarıyor gibiydi.
serap

3

SocketHem istemcideki hem de sunucu ucundaki örneğin açıkça çağırılması gerektiğinden bahsedilmelidir close(). Uçlardan yalnızca biri devreye girerse close(), yuva CLOSE_WAIT durumunda kalacaktır.


3

Soketleri sskomutla zorla kapatabilirsiniz ; ssKomut netstat için soket istatistik ve görüntüler bilgileri benzer şekilde (daha basit olmasına rağmen ve daha hızlı) dökümü için kullanılan bir araçtır.

CLOSE_WAIT durumunda herhangi bir soketi öldürmek için bunu çalıştırın (kök olarak)

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

1

Ayrıca, programınız yeni bir süreç ortaya çıkarsa, bu işlemin tüm açık tutamaçlarınızı devralabileceğini de belirtmek gerekir. Kendi programınızdan sonra bile, bu miras kalan tutamaçlar, öksüz çocuk süreci aracılığıyla hala canlı olabilir. Netstat'ta da aynı görünmeleri gerekmez. Ancak yine de, bu alt süreç yaşarken soket CLOSE_WAIT'de takılacak.

ADB'yi çalıştırdığım bir vakam vardı. ADB, zaten çalışmıyorsa, bir sunucu işlemi oluşturur. Bu, başlangıçta tüm tutamaçlarımı devraldı, ancak araştırırken hiçbirine sahip olarak görünmedi (aynısı hem macOS hem de Windows için geçerliydi - Linux hakkında emin değilim).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.