Bagaimana cara menghapus koneksi soket CLOSE_WAIT

91

Saya telah menulis program kecil yang berinteraksi dengan server di port tertentu. Program ini berfungsi dengan baik, tetapi:

Setelah program berhenti tiba-tiba, dan sejak koneksi soket ditampilkan dalam CLOSE_WAITstatus. Jika saya mencoba menjalankan program, program itu hang dan saya harus memaksanya menutup, yang mengakumulasi lebih banyak CLOSE_WAIT koneksi soket.

Apakah ada cara untuk menghilangkan koneksi ini?

Dilletante
sumber
4
Anda tidak bisa (dan tidak boleh). CLOSE_WAIT adalah keadaan yang ditentukan oleh TCP untuk koneksi yang ditutup menunggu mitra untuk mengakui ini.
vonbrand
1
Lihat juga unix.stackexchange.com/questions/10106/… ... yang saya tidak akan memilih sebagai duplikat, karena itu akan menutup pertanyaan sebagai di luar topik.
derobert
4
@vonbrand Tidak, justru sebaliknya. Ini adalah status untuk koneksi yang telah ditutup oleh rekan dan menunggu aplikasi lokal menutup akhirnya.
Marquis dari Lorne
Jika Anda menggunakan Commons HttpClient maka nuxeo.com/blog/… memiliki banyak informasi yang relevan. Dari RFC 2616, Bagian 14: Aplikasi HTTP / 1.1 yang tidak mendukung koneksi persisten HARUS menyertakan opsi koneksi "tutup" di setiap pesan.
Mayank Ahuja

Jawaban:

79

CLOSE_WAITberarti program Anda masih berjalan, dan belum menutup soket (dan kernel sedang menunggu untuk melakukannya). Tambahkan -pke netstatuntuk mendapatkan pid, dan kemudian matikan dengan lebih kuat (dengan SIGKILLjika diperlukan). Itu harus menyingkirkan CLOSE_WAITsoket Anda . Anda juga dapat menggunakan psuntuk menemukan pid.

SO_REUSEADDRuntuk server dan TIME_WAITsoket, jadi tidak berlaku di sini.

derobert
sumber
2
baik ... proses kiling mungkin bukan yang terbaik jika program itu membuka banyak koneksi, hanya beberapa dari mereka yang tetap di "CLOSE_WAIT": dalam kasus ini mematikan proses mungkin sama sekali tidak mungkin atau tidak sesuai (program masih bekerja dan menyediakan layanan, dengan koneksi lainnya). Hanya menutup koneksi yang tertunda akan jauh lebih tepat. tetapi memang biasanya program itu sendiri yang tidak menutup koneksi secara lokal (CLOSE_WAIT berarti menerima 'FIN' dari ujung lain dan program hanya perlu menutup koneksi secara lokal). Laporan bug mungkin sesuai
Olivier Dulac
40

Seperti yang dijelaskan oleh Crist Clark .

CLOSE_WAIT berarti bahwa ujung lokal koneksi telah menerima FIN dari ujung yang lain, tetapi OS sedang menunggu program di ujung lokal untuk benar-benar menutup koneksinya.

Masalahnya adalah program Anda yang berjalan di mesin lokal tidak menutup soket. Ini bukan masalah penyetelan TCP. Koneksi dapat (dan dengan benar) tetap di CLOSE_WAIT selamanya selama program menahan koneksi terbuka.

Setelah program lokal menutup soket, OS dapat mengirim FIN ke ujung jarak jauh yang mentransisikan Anda ke LAST_ACK sementara Anda menunggu ACK FIN. Setelah diterima, koneksi selesai dan turun dari tabel koneksi (jika akhir Anda di CLOSE_WAIT Anda tidak berakhir dalam status TIME_WAIT).

pengguna2618402
sumber
4
bagaimana cara menutup socket ??
Divyang Shah
1
Anda menutup pegangan Anda harus ke soket yang Anda buka. Gunakan close()atau closesocket(), tergantung pada platform mana yang Anda gunakan.
Remy Lebeau
8

Saya juga mengalami masalah yang sama dengan server Tomcat terbaru (7.0.40). Ini menjadi non-responsif sekali selama beberapa hari.

Untuk melihat koneksi terbuka, Anda dapat menggunakan:

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

Seperti yang disebutkan dalam posting ini , Anda dapat menggunakan /proc/sys/net/ipv4/tcp_keepalive_timeuntuk melihat nilainya. Nilainya tampaknya dalam hitungan detik dan default ke 7200 (yaitu 2 jam).

Untuk mengubahnya, Anda perlu mengedit /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`
Amil Waduwawara
sumber
4
jawabannya membingungkan. Anda mengatakan status non-responsif telah hilang selama beberapa hari .. tetapi kemudian Anda juga mencoba menyetel waktu tetap hidup menjadi hanya 120 detik. bahkan dengan nilai default (7200 detik), seharusnya tidak bertahan selama beberapa hari, bukan?
fanchyna
8

Meskipun terlalu banyak koneksi CLOSE_WAIT berarti ada yang salah dengan kode Anda pada awalnya dan ini diterima sebagai praktik yang tidak baik.

Anda mungkin ingin memeriksa: https://github.com/rghose/kill-close-wait-connections

Apa yang dilakukan skrip ini adalah mengirimkan ACK yang telah ditunggu oleh koneksi.

Inilah yang berhasil bagi saya.

fatamorgana
sumber
Anda mengirim tindakan ke soket tunggu dekat. dengan tidak berfungsi .. jika berhasil, mengapa?
Chinaxing
Saya menebak, OS telah mengirim FIN ke host jarak jauh. Host jarak jauh mungkin tidak dapat membalas dengan ACK yang diharapkan soket.
fatamorgana
ya, itu benar (dari kode kernel). tetapi saya juga ragu tentang SEQ dari paket yang Anda kirim, yaitu "10", apakah kernel tidak memeriksanya?
Chinaxing
Mungkin tidak. Saya pikir saya mencoba dengan banyak nomor acak, dan sepertinya berhasil.
fatamorgana
3

Harus disebutkan bahwa Socketinstance di klien dan ujung server perlu dipanggil secara eksplisit close(). Jika hanya salah satu ujung yang dipanggil close(), soket akan tetap dalam status CLOSE_WAIT.

Binita Bharati
sumber
3

Anda dapat menutup soket secara paksa dengan ssperintah; yang ssperintah adalah alat yang digunakan untuk membuang statistik socket dan menampilkan informasi dalam cara yang sama (meskipun sederhana dan lebih cepat) untuk netstat.

Untuk mematikan soket apa pun dalam status CLOSE_WAIT, jalankan ini (sebagai root)

$ ss --tcp state CLOSE-WAIT --kill
Mustapha Hadid
sumber
1

Perlu juga dicatat bahwa jika program Anda memunculkan proses baru, proses itu mungkin mewarisi semua pegangan yang Anda buka. Bahkan setelah program closs Anda sendiri, pegangan yang diwariskan itu masih bisa hidup melalui proses anak yatim piatu. Dan mereka tidak selalu muncul sama di netstat. Tapi tetap saja, soket akan tetap berada di CLOSE_WAIT saat proses anak ini hidup.

Saya memiliki kasus di mana saya menjalankan ADB. ADB sendiri memunculkan proses server jika belum berjalan. Ini mewarisi semua pegangan saya pada awalnya, tetapi tidak muncul sebagai memiliki salah satu dari mereka ketika saya menyelidiki (hal yang sama berlaku untuk macOS dan Windows - tidak yakin tentang Linux).

Ian
sumber