Untuk saran saya, silakan baca bagian terakhir: “Kapan menggunakan SO_LINGER dengan waktu tunggu 0” .
Sebelum kita sampai pada kuliah kecil itu tentang:
- Pengakhiran TCP normal
TIME_WAIT
FIN
, ACK
danRST
Pengakhiran TCP normal
Urutan terminasi TCP normal terlihat seperti ini (disederhanakan):
Kami memiliki dua rekan: A dan B
- A panggilan
close()
- A mengirim
FIN
ke B
- A masuk ke
FIN_WAIT_1
negara bagian
- B menerima
FIN
- B mengirim
ACK
ke A
- B masuk ke
CLOSE_WAIT
negara bagian
- A menerima
ACK
- A masuk ke
FIN_WAIT_2
negara bagian
- B. panggilan
close()
- B mengirim
FIN
ke A
- B masuk ke
LAST_ACK
negara bagian
- A menerima
FIN
- A mengirim
ACK
ke B
- A masuk ke
TIME_WAIT
negara bagian
- B menerima
ACK
- B pergi ke
CLOSED
negara - yaitu dihapus dari tabel soket
WAKTU MENUNGGU
Jadi rekan yang memulai penghentian - yaitu panggilan close()
pertama - akan berakhir di TIME_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 panggilan close()
akan menyebabkan urutan penghentian normal tidak dimulai.
Sebaliknya, rekan yang mengatur opsi ini dan memanggil close()
akan mengirim RST
(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 menelepon close()
- mulai sekarang disebut abortive close - dalam aplikasi server.
Namun, situasi tertentu tetap harus dilakukan:
- Jika klien aplikasi server Anda berperilaku tidak semestinya (waktu habis, mengembalikan data yang tidak valid, dll.) Penutupan yang gagal masuk akal untuk menghindari macet
CLOSE_WAIT
atau berakhir di TIME_WAIT
status.
- Jika Anda harus memulai ulang aplikasi server Anda yang saat ini memiliki ribuan koneksi klien, Anda dapat mempertimbangkan untuk mengatur opsi soket ini untuk menghindari ribuan soket server masuk
TIME_WAIT
(saat menelepon close()
dari ujung server) karena ini mungkin mencegah server mendapatkan port yang tersedia untuk koneksi klien baru setelah di-restart.
- Pada halaman 202 di buku tersebut secara khusus mengatakan: "Ada keadaan tertentu yang mengharuskan menggunakan fitur ini untuk mengirim penutupan yang gagal. Salah satu contohnya adalah server terminal RS-232, yang mungkin hang selamanya saat
CLOSE_WAIT
mencoba mengirimkan data ke terminal yang macet port, tetapi akan dengan benar mengatur ulang port yang macet jika harus RST
membuang data yang tertunda. "
Saya akan merekomendasikan ini artikel panjang yang saya percaya memberikan jawaban yang sangat baik untuk pertanyaan Anda.