Tidak ada jawaban yang ada yang memberi tahu orang bagaimana shutdown
dan close
bekerja pada tingkat protokol TCP, jadi perlu menambahkan ini.
Koneksi TCP standar diakhiri oleh finalisasi 4 arah:
- Setelah peserta tidak memiliki data lagi untuk dikirim, ia mengirim paket FIN ke yang lain
- Pihak lain mengembalikan ACK untuk FIN.
- Ketika pihak lain juga selesai mentransfer data, ia mengirim paket FIN lain
- Peserta awal mengembalikan ACK dan menyelesaikan transfer.
Namun, ada cara "muncul" lain untuk menutup koneksi TCP:
- Seorang peserta mengirim paket RST dan meninggalkan koneksi
- Sisi lain menerima RST dan kemudian meninggalkan koneksi juga
Dalam pengujian saya dengan Wireshark, dengan opsi soket default, shutdown
mengirim paket FIN ke ujung lain tetapi hanya itu yang dilakukannya. Sampai pihak lain mengirimi Anda paket FIN, Anda masih dapat menerima data. Setelah ini terjadi, Anda Receive
akan mendapatkan hasil ukuran 0. Jadi, jika Anda adalah orang pertama yang mematikan "kirim", Anda harus menutup soket setelah Anda selesai menerima data.
Di sisi lain, jika Anda menelepon close
saat koneksi masih aktif (sisi lain masih aktif dan Anda mungkin memiliki data yang belum terkirim di buffer sistem juga), paket RST akan dikirim ke sisi lain. Ini bagus untuk kesalahan. Misalnya, jika Anda berpikir pihak lain memberikan data yang salah atau menolak memberikan data (serangan DOS?), Anda dapat langsung menutup soket.
Pendapat saya tentang aturan adalah:
- Pertimbangkan
shutdown
sebelumnya close
jika memungkinkan
- Jika Anda selesai menerima (0 data ukuran diterima) sebelum Anda memutuskan untuk mematikan, tutup koneksi setelah pengiriman terakhir (jika ada) selesai.
- Jika Anda ingin menutup koneksi secara normal, matikan koneksi (dengan SHUT_WR, dan jika Anda tidak peduli tentang menerima data setelah titik ini, dengan SHUT_RD juga), dan tunggu sampai Anda menerima data ukuran 0, dan kemudian tutup stopkontak.
- Bagaimanapun, jika ada kesalahan lain terjadi (timeout misalnya), cukup tutup soketnya.
Implementasi ideal untuk SHUT_RD dan SHUT_WR
Berikut ini belum diuji, percaya dengan risiko Anda sendiri. Namun, saya percaya ini adalah cara yang masuk akal dan praktis untuk melakukan sesuatu.
Jika TCP stack menerima shutdown hanya dengan SHUT_RD, itu akan menandai koneksi ini karena tidak ada lagi data yang diharapkan. Segala permintaan yang tertunda dan selanjutnya read
(terlepas dari utas mana pun mereka berada) kemudian akan dikembalikan dengan hasil ukuran nol. Namun, koneksi masih aktif dan dapat digunakan - Anda masih dapat menerima data OOB, misalnya. Juga, OS akan menjatuhkan data apa pun yang diterimanya untuk koneksi ini. Tapi itu saja, tidak ada paket yang akan dikirim ke sisi lain.
Jika TCP stack menerima shutdown hanya dengan SHUT_WR, itu akan menandai koneksi ini karena tidak ada lagi data yang dapat dikirim. Semua permintaan penulisan yang tertunda akan selesai, tetapi permintaan penulisan berikutnya akan gagal. Selain itu, paket FIN akan dikirim ke pihak lain untuk memberi tahu mereka bahwa kami tidak memiliki lebih banyak data untuk dikirim.