socket.shutdown vs socket.close

122

Saya baru-baru ini melihat sedikit kode yang terlihat seperti ini (dengan kaus kaki menjadi objek soket tentunya):

sock.shutdown(socket.SHUT_RDWR)
sock.close()

Apa sebenarnya tujuan memanggil shutdown pada soket dan kemudian menutupnya? Jika ada perbedaan, soket ini digunakan untuk IO non-pemblokiran.

Jason Baker
sumber

Jawaban:

38

Berikut salah satu penjelasannya :

Setelah soket tidak lagi diperlukan, program pemanggil dapat membuang soket dengan menerapkan subrutin dekat ke deskriptor soket. Jika soket pengiriman yang andal memiliki data yang terkait dengannya saat penutupan terjadi, sistem akan terus mencoba mentransfer data. Namun, jika data masih belum terkirim, sistem akan membuang data tersebut. Jika program aplikasi tidak menggunakan data yang tertunda, ia dapat menggunakan subrutin shutdown pada soket sebelum menutupnya.

Bob Nadler
sumber
241

Menelepon closedanshutdown memiliki dua efek berbeda pada soket yang mendasarinya.

Hal pertama yang perlu diperhatikan adalah bahwa soket adalah sumber daya di OS yang mendasarinya dan beberapa proses dapat menangani soket dasar yang sama.

Ketika Anda memanggilnya closemengurangi jumlah pegangan satu dan jika jumlah pegangan telah mencapai nol maka soket dan koneksi terkait melewati prosedur penutupan normal (secara efektif mengirim FIN / EOF ke peer) dan soket dibatalkan alokasinya.

Hal yang perlu diperhatikan disini adalah jika jumlah pegangan tidak mencapai nol karena proses lain masih mempunyai pegangan ke soket maka koneksi tidak ditutup dan soket tidak dibatalkan alokasinya.

Di sisi lain, panggilan shutdownuntuk membaca dan menulis menutup koneksi yang mendasarinya dan mengirimkan FIN / EOF ke peer terlepas dari berapa banyak proses yang ditangani ke soket. Namun, itu tidak membatalkan alokasi soket dan Anda masih harus menutup setelahnya.

Robert S. Barnes
sumber
jawaban yang bagus, saya tidak pernah repot-repot untuk mencari tahu apa shutdown():)
Matt Joiner
2
Bisakah shutdown () untuk dibaca menyebabkannya mengirim paket FIN? yaitu shutdown (sock_fd, 1);
ernesto
Apakah pintar untuk selalu menelepon .shutdown()dan di saluran berikutnya .close()? Atau haruskah ada penundaan di antaranya?
Luc
@Luc Sepenuhnya tergantung pada apa yang Anda lakukan.
Robert S. Barnes
2
@Luc Kemudian tutup saja baik-baik saja selama tidak ada proses lain yang menangani soket.
Robert S. Barnes
17

Penjelasan shutdown dan close: Graceful shutdown (msdn)

Shutdown (dalam kasus Anda) menunjukkan ke ujung lain koneksi tidak ada niat lebih lanjut untuk membaca atau menulis ke soket. Kemudian tutup membebaskan memori apa pun yang terkait dengan soket.

Menghilangkan pematian dapat menyebabkan soket tetap berada di tumpukan OS sampai koneksi telah ditutup dengan baik.

IMO nama 'shutdown' dan 'close' menyesatkan, 'close' dan 'destroy' akan menekankan perbedaan mereka.

Dale Reidy
sumber
Itu tidak menunjukkan ke ujung yang lain bahwa tidak ada niat lebih lanjut untuk membaca. Shutdown untuk membaca tidak mengirim apapun ke peer.
Marquis dari Lorne
7

itu disebutkan tepat di Socket Programming HOWTO ( py2 / py3 )

Memutuskan

Sebenarnya, Anda seharusnya menggunakan shutdownsoket sebelum Anda closemenggunakannya. Ini shutdownadalah penasehat untuk soket di ujung lain. Bergantung pada argumen yang Anda sampaikan, itu bisa berarti “ Saya tidak akan mengirim lagi, tetapi saya akan tetap mendengarkan ”, atau “ Saya tidak mendengarkan, selamat datang! ". Kebanyakan pustaka soket, bagaimanapun, begitu terbiasa dengan pemrogram yang lalai menggunakan bagian etiket yang biasanya closesama dengan shutdown(); close(). Jadi dalam kebanyakan situasi, shutdown eksplisit tidak diperlukan.

...

mykhal
sumber
Informasi ini tidak benar. Anda hanya perlu mematikan soket untuk menulis jika (1) Anda telah melakukan fork proses dan pasti ingin mengirim FIN sekarang, atau (2) Anda terlibat dalam protokol saling baca-ke-EOS sehingga kedua peer menutup pada waktu bersamaan. Kalau tidak, close()sudah cukup. Dokumentasi Python harus diperbaiki.
Marquis dari Lorne
4

Bukankah kode di atas ini salah?

Penutupan panggilan langsung setelah panggilan shutdown mungkin membuat kernel membuang semua buffer keluar.

Menurut http://blog.netherlabs.nl/articles/2009/01/18/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable seseorang perlu menunggu antara shutdown dan tutup sampai pembacaan kembali 0.

Kristen
sumber
Tidak benar. Kernel hanya akan membuang buffer keluar jika koneksi telah disetel ulang, yang dapat terjadi jika aplikasi lokal belum membaca semua data masuk tertunda yang telah tiba, atau jika peer telah mengacaukan SO_LINGER, yang seharusnya tidak mereka lakukan . Tidak ada keharusan untuk tidur, atau bahkan untuk memanggil shutdown sebelum tutup. Ada banyak informasi yang salah di luar sana tentang masalah ini.
Marquis dari Lorne
1

Shutdown (1), memaksa soket no untuk mengirim lebih banyak data

Ini berguna di

1- Pembilasan penyangga

2- Deteksi kesalahan yang aneh

3- Penjagaan yang aman

Biar saya jelaskan lebih lanjut, ketika Anda mengirim data dari A ke B, itu tidak dijamin akan dikirim ke B, itu hanya dijamin akan dikirim ke buffer A os, yang pada gilirannya mengirimkannya ke buffer B os

Jadi dengan memanggil shutdown (1) pada A, Anda mengosongkan buffer A dan kesalahan akan muncul jika buffer tidak kosong, yaitu: data belum dikirim ke peer

Bagaimanapun ini tidak dapat dibatalkan, jadi Anda dapat melakukannya setelah Anda benar-benar mengirim semua data Anda dan Anda ingin memastikan bahwa itu setidaknya di peer os buffer

pengguna306166
sumber
Shutdown tidak memaksa flush. Situasi buffering tidak berubah. Dan jika buffer tidak kosong, tidak ada kesalahan yang dimunculkan. FIN hanya mengantri di belakang data yang menunggu keputusan. Jawabannya salah sama sekali.
Marquis dari Lorne