Saya rasa saya memahami arti formal dari opsi tersebut. Di beberapa kode lama yang saya tangani sekarang, opsi digunakan. Pelanggan mengeluhkan RST sebagai respon terhadap FIN dari sisinya pada koneksi yang ditutup dari sisinya.
Saya tidak yakin saya dapat menghapusnya dengan aman, karena saya tidak mengerti kapan harus digunakan.
Bisakah Anda memberi contoh kapan opsi akan diperlukan?
Jawaban:
Alasan umum untuk menyetel waktu
SO_LINGER
tunggu nol adalah untuk menghindari koneksi dalam jumlah besar yang berada dalamTIME_WAIT
status, mengikat semua sumber daya yang tersedia di server.Ketika koneksi TCP ditutup dengan bersih, ujung yang memulai penutupan ("tutup aktif") berakhir dengan koneksi diam
TIME_WAIT
selama beberapa menit. Jadi, jika protokol Anda adalah protokol di mana server memulai koneksi untuk menutup, dan melibatkan koneksi jangka pendek dalam jumlah yang sangat besar, maka mungkin rentan terhadap masalah ini.Ini bukan ide yang bagus -
TIME_WAIT
ada karena suatu alasan (untuk memastikan bahwa paket yang tersesat dari koneksi lama tidak mengganggu koneksi baru). Ide yang lebih baik untuk mendesain ulang protokol Anda ke protokol di mana klien memulai koneksi dekat, jika memungkinkan.sumber
TIME_WAIT
keinginan klien tidak akan merugikan. Ingat seperti yang tertulis dalam "Pemrograman Jaringan UNIX" edisi ketiga (Stevens dkk) halaman 203: "Status TIME_WAIT adalah teman Anda dan ada untuk membantu kami. Daripada mencoba menghindari keadaan, kami harus memahaminya (Bagian 2.7) . "Untuk saran saya, silakan baca bagian terakhir: “Kapan menggunakan SO_LINGER dengan waktu tunggu 0” .
Sebelum kita sampai pada kuliah kecil itu tentang:
TIME_WAIT
FIN
,ACK
danRST
Pengakhiran TCP normal
Urutan terminasi TCP normal terlihat seperti ini (disederhanakan):
Kami memiliki dua rekan: A dan B
close()
FIN
ke BFIN_WAIT_1
negara bagianFIN
ACK
ke ACLOSE_WAIT
negara bagianACK
FIN_WAIT_2
negara bagianclose()
FIN
ke ALAST_ACK
negara bagianFIN
ACK
ke BTIME_WAIT
negara bagianACK
CLOSED
negara - yaitu dihapus dari tabel soketWAKTU MENUNGGU
Jadi rekan yang memulai penghentian - yaitu panggilan
close()
pertama - akan berakhir diTIME_WAIT
status.Untuk memahami mengapa
TIME_WAIT
negara adalah teman kita, silakan baca bagian 2.7 dalam "Pemrograman Jaringan UNIX" edisi ketiga oleh Stevens et al (halaman 43).Namun, ini bisa menjadi masalah dengan banyak soket di dalamnya
TIME_WAIT
status di server karena pada akhirnya dapat mencegah koneksi baru diterima.Untuk mengatasi masalah ini, saya telah melihat banyak yang menyarankan untuk menyetel opsi soket SO_LINGER dengan batas waktu 0 sebelum menelepon
close()
. Namun, ini adalah solusi yang buruk karena menyebabkan koneksi TCP diakhiri dengan kesalahan.Sebaliknya, rancang protokol aplikasi Anda sehingga penghentian koneksi selalu dimulai dari sisi klien. Jika klien selalu tahu ketika telah membaca semua data yang tersisa, ia dapat memulai urutan penghentian. Sebagai contoh, browser mengetahui dari
Content-Length
header HTTP ketika telah membaca semua data dan dapat memulai penutupan. (Saya tahu bahwa di HTTP 1.1 itu akan membuatnya tetap terbuka untuk sementara waktu untuk kemungkinan digunakan kembali, dan kemudian menutupnya.)Jika server perlu menutup koneksi, rancang protokol aplikasi sehingga server meminta klien untuk menelepon
close()
.Kapan menggunakan SO_LINGER dengan waktu tunggu 0
Sekali lagi, menurut "Pemrograman Jaringan UNIX" edisi ketiga halaman 202-203, pengaturan
SO_LINGER
dengan batas waktu 0 sebelum panggilanclose()
akan menyebabkan urutan penghentian normal tidak dimulai.Sebaliknya, rekan yang mengatur opsi ini dan memanggil
close()
akan mengirimRST
(reset koneksi) yang menunjukkan kondisi kesalahan dan ini akan dianggap di ujung lain. Anda biasanya akan melihat kesalahan seperti "Sambungan disetel ulang oleh rekan".Oleh karena itu, dalam situasi normal, adalah ide yang sangat buruk untuk menyetel
SO_LINGER
dengan batas waktu 0 sebelum meneleponclose()
- mulai sekarang disebut abortive close - dalam aplikasi server.Namun, situasi tertentu tetap harus dilakukan:
CLOSE_WAIT
atau berakhir diTIME_WAIT
status.TIME_WAIT
(saat meneleponclose()
dari ujung server) karena ini mungkin mencegah server mendapatkan port yang tersedia untuk koneksi klien baru setelah di-restart.CLOSE_WAIT
mencoba mengirimkan data ke terminal yang macet port, tetapi akan dengan benar mengatur ulang port yang macet jika harusRST
membuang data yang tertunda. "Saya akan merekomendasikan ini artikel panjang yang saya percaya memberikan jawaban yang sangat baik untuk pertanyaan Anda.
sumber
TIME_WAIT
adalah teman hanya jika tidak mulai menimbulkan masalah: stackoverflow.com/questions/1803566/…Ketika berlama-lama aktif tetapi waktu tunggu nol, tumpukan TCP tidak menunggu data yang tertunda dikirim sebelum menutup koneksi. Data bisa hilang karena ini tetapi dengan menyetel berlama-lama dengan cara ini Anda menerima ini dan meminta agar koneksi segera disetel ulang daripada ditutup dengan anggun. Hal ini menyebabkan RST dikirim daripada FIN biasa.
Terima kasih kepada EJP atas komentarnya, lihat di sini untuk detailnya.
sumber
Apakah Anda dapat menghapus sisa kode Anda dengan aman atau tidak tergantung pada jenis aplikasi Anda: apakah itu "klien" (membuka koneksi TCP dan menutupnya secara aktif terlebih dahulu) atau apakah itu "server" (mendengarkan TCP terbuka dan menutupnya setelah pihak lain memulai penutupan)?
Jika aplikasi Anda memiliki cita rasa "klien" (menutup dulu) DAN Anda memulai & menutup sejumlah besar koneksi ke server yang berbeda (misalnya, saat aplikasi Anda adalah aplikasi pemantauan yang mengawasi jangkauan dari sejumlah besar server yang berbeda) aplikasi Anda memiliki masalah bahwa semua koneksi klien Anda macet dalam status TIME_WAIT. Kemudian, saya akan merekomendasikan untuk mempersingkat waktu tunggu ke nilai yang lebih kecil daripada default untuk tetap mematikan dengan baik tetapi membebaskan sumber daya koneksi klien sebelumnya. Saya tidak akan menyetel batas waktu ke 0, karena 0 tidak dimatikan dengan baik dengan FIN tetapi gagal dengan RST.
Jika aplikasi Anda memiliki rasa "klien" dan harus mengambil sejumlah besar file kecil dari server yang sama, Anda tidak boleh memulai koneksi TCP baru per file dan berakhir dengan koneksi klien dalam jumlah besar di TIME_WAIT, tetapi biarkan koneksi tetap terbuka dan ambil semua data melalui koneksi yang sama. Opsi berlama-lama dapat dan harus dihapus.
Jika aplikasi Anda adalah sebuah "server" (tutup kedua sebagai reaksi terhadap penutupan peer), pada close () koneksi Anda dimatikan dengan baik dan sumber daya dibebaskan karena Anda tidak memasuki status TIME_WAIT. Linger sebaiknya tidak digunakan. Tetapi jika aplikasi server Anda memiliki proses pengawasan yang mendeteksi koneksi terbuka yang tidak aktif menganggur untuk waktu yang lama ("panjang" harus ditentukan), Anda dapat mematikan koneksi yang tidak aktif ini dari sisi Anda - melihatnya sebagai jenis penanganan kesalahan - dengan pematian yang gagal. Ini dilakukan dengan menyetel linger timeout ke 0. close () kemudian akan mengirim RST ke klien, memberitahunya bahwa Anda marah :-)
sumber
Di server, Anda mungkin ingin mengirim
RST
alih-alihFIN
saat memutuskan klien yang berperilaku tidak semestinya. Lompatan ituFIN-WAIT
diikuti olehTIME-WAIT
status soket di server, yang mencegah menipisnya sumber daya server, dan, karenanya, melindungi dari serangan penolakan layanan semacam ini.sumber
Saya suka pengamatan Maxim bahwa serangan DOS dapat menghabiskan sumber daya server. Itu juga terjadi tanpa musuh yang benar-benar jahat.
Beberapa server harus berurusan dengan 'serangan DOS yang tidak disengaja' yang terjadi ketika aplikasi klien memiliki bug dengan kebocoran koneksi, di mana mereka terus membuat koneksi baru untuk setiap perintah baru yang mereka kirim ke server Anda. Dan kemudian mungkin akhirnya menutup koneksi mereka jika mereka terkena tekanan GC, atau mungkin koneksi akhirnya timeout.
Skenario lain adalah ketika skenario 'semua klien memiliki alamat TCP yang sama'. Kemudian koneksi klien hanya dapat dibedakan dengan nomor port (jika terhubung ke satu server). Dan jika klien mulai berputar cepat membuka / menutup koneksi karena alasan apa pun, mereka dapat menghabiskan ruang tuple (addr klien + port, server IP + port).
Jadi saya pikir server mungkin paling disarankan untuk beralih ke strategi Linger-Zero ketika mereka melihat sejumlah besar soket dalam status TIME_WAIT - meskipun itu tidak memperbaiki perilaku klien, ini mungkin mengurangi dampaknya.
sumber
Soket pendengar pada server dapat menggunakan linger dengan waktu 0 untuk memiliki akses untuk mengikat kembali ke soket segera dan untuk mengatur ulang klien yang koneksinya belum selesai terhubung. TIME_WAIT adalah sesuatu yang hanya menarik ketika Anda memiliki jaringan multi-jalur dan dapat berakhir dengan paket yang tidak dipesan atau berurusan dengan pemesanan paket jaringan yang aneh / waktu kedatangan.
sumber