FYI jika Anda memilih untuk menggunakan waktu tunggu ... Anda perlu tahu cara menangani batas waktu. Pertanyaan SO ini berbicara tentang penanganan ketika batas waktu terjadi: stackoverflow.com/questions/16745409
Trevor Boyd Smith
Jawaban:
126
Pendekatan tipikal adalah menggunakan select () untuk menunggu hingga data tersedia atau hingga batas waktu terjadi. Telepon hanya recv()jika data benar-benar tersedia. Untuk amannya, kami juga menyetel soket ke mode non-pemblokiran untuk menjamin bahwa recv()tidak akan pernah memblokir tanpa batas. select()juga dapat digunakan untuk menunggu lebih dari satu soket dalam satu waktu.
Jika Anda memiliki banyak deskriptor file yang terbuka, poll () adalah alternatif yang lebih efisien untuk select().
Pilihan lain adalah mengatur batas waktu untuk semua operasi pada soket yang digunakan socket.settimeout(), tetapi saya melihat bahwa Anda secara eksplisit menolak solusi itu di jawaban lain.
penggunaan selectitu bagus, tetapi bagian di mana Anda mengatakan "Anda tidak bisa" menyesatkan, karena memang ada socket.settimeout().
nosklo
1
Sekarang lebih baik, tetapi saya tidak melihat di mana jawabannya "ditolak secara eksplisit".
nosklo
7
Satu kehati-hatian dalam menggunakan select- jika Anda menjalankan mesin Windows, selectbergantung pada pustaka WinSock, yang memiliki kebiasaan untuk kembali segera setelah beberapa data tiba, tetapi tidak harus semuanya . Jadi, Anda perlu memasukkan loop untuk terus menelepon select.select()hingga semua data diterima. Bagaimana Anda tahu bahwa Anda telah mendapatkan semua data (sayangnya) terserah Anda untuk mengetahuinya - ini mungkin berarti mencari string terminator, sejumlah byte, atau hanya menunggu waktu tunggu yang ditentukan.
JDM
4
Mengapa perlu mengatur soket tanpa pemblokiran? Saya tidak berpikir itu penting untuk panggilan pilih (dan itu memblokir sampai deskriptor dapat dibaca atau batas waktu berakhir dalam kasus ini) dan recv () tidak akan memblokir jika pemilihan puas. Saya mencobanya menggunakan recvfrom () dan tampaknya berfungsi dengan benar tanpa setblocking (0).
HankB
1
Apakah ready[0]hanya salah jika tidak ada bagian dalam respons server?
Tidak ada waktu tunggu penerimaan (setidaknya ketika saya mencobanya). Hanya accept () yang waktunya habis.
Oren S
9
Socket.recv () tampaknya waktu habis bagi saya setelah menyetel socket.settimeout (), persis seperti yang dimaksudkan. Apakah saya mengada-ada? Adakah yang bisa mengkonfirmasi ini?
Aeonaut
3
@Aeonaut Saya pikir kali ini recv () sebagian besar waktu, tetapi ada kondisi balapan. Dalam socket.recv () Python (2.6) memanggil select / poll secara internal dengan batas waktu dan kemudian recv () dipanggil tepat setelahnya. Jadi jika Anda menggunakan soket pemblokiran dan di antara 2 panggilan ini, titik akhir lainnya lumpuh, Anda bisa berakhir tanpa batas waktu di recv (). Jika Anda menggunakan soket non-pemblokiran, python tidak memanggil select.select secara internal, jadi saya pikir jawaban Daniel Stutzbach adalah cara yang benar.
emil.p.stanchev
4
Sebenarnya, saya mungkin salah paham saat select () kembali, jadi gores komentar sebelumnya. Beej's Guide mengatakan bahwa di atas adalah cara yang valid untuk mengimplementasikan batas waktu di recv: beej.us/guide/bgnet/output/html/singlepage/… jadi saya percaya adalah sumber otoratif.
emil.p.stanchev
2
Saya tidak yakin mengapa solusi yang menggunakan selectlebih disukai ketika solusi ini adalah satu liner (lebih mudah dirawat, lebih sedikit risiko dalam penerapan yang salah) dan menggunakan pilihan di bawah tenda (penerapannya sama dengan jawaban @DanielStuzbach).
Saya pikir dia mendapatkan hal yang sama saya di mana tidak peduli bagaimana Anda menyodok dan mendorong fungsi ini hang. Saya sudah mencoba 2 atau 4 waktu tunggu sekarang dan masih hang. settimeout juga hang.
Casey Daniel
1
Saat Anda memanggil .settimeout()lebih dari sekali, Anda dapat memanggil setdefaulttimeout()metode ini sejak awal.
mvarge
12
Anda dapat menyetel batas waktu sebelum menerima respons dan setelah menerima respons, setel kembali ke Tidak Ada:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
Waktu tunggu yang Anda cari adalah batas waktu soket sambungan, bukan waktu tunggu soket utama, jika Anda menerapkan sisi server. Dengan kata lain, ada waktu tunggu lain untuk objek soket sambungan, yang merupakan keluaran socket.accept()metode. Karena itu:
sock.listen(1)
connection, client_address = sock.accept()
connection.settimeout(5)# This is the one that affects recv() method.
connection.gettimeout()# This should result 5
sock.gettimeout()# This outputs None when not set previously, if I remember correctly.
Jika Anda menerapkan sisi klien, itu akan sederhana.
Seperti yang disebutkan dalam balasan sebelumnya, Anda dapat menggunakan sesuatu seperti: .settimeout()
Misalnya:
import socket
s = socket.socket()
s.settimeout(1)# Sets the socket to timeout after 1 second of no activity
host, port ="somehost",4444
s.connect((host, port))
s.send("Hello World!\r\n")try:
rec = s.recv(100)# try to receive 100 bytesexcept socket.timeout:# fail after 1 second of no activityprint("Didn't receive data! [Timeout]")finally:
s.close()
Anda dapat menggunakan socket.settimeout()yang menerima argumen integer yang mewakili jumlah detik. Misalnya, socket.settimeout(1)akan menyetel waktu tunggu ke 1 detik
Ini menyediakan soket buffer, ini menyediakan banyak fungsi yang sangat berguna seperti:
.recv_until()#recv until occurrence of bytes.recv_closed()#recv until close.peek()#peek at buffer but don't pop values.settimeout()#configure timeout (including recv timeout)
Jawaban:
Pendekatan tipikal adalah menggunakan select () untuk menunggu hingga data tersedia atau hingga batas waktu terjadi. Telepon hanya
recv()
jika data benar-benar tersedia. Untuk amannya, kami juga menyetel soket ke mode non-pemblokiran untuk menjamin bahwarecv()
tidak akan pernah memblokir tanpa batas.select()
juga dapat digunakan untuk menunggu lebih dari satu soket dalam satu waktu.Jika Anda memiliki banyak deskriptor file yang terbuka, poll () adalah alternatif yang lebih efisien untuk
select()
.Pilihan lain adalah mengatur batas waktu untuk semua operasi pada soket yang digunakan
socket.settimeout()
, tetapi saya melihat bahwa Anda secara eksplisit menolak solusi itu di jawaban lain.sumber
select
itu bagus, tetapi bagian di mana Anda mengatakan "Anda tidak bisa" menyesatkan, karena memang adasocket.settimeout()
.select
- jika Anda menjalankan mesin Windows,select
bergantung pada pustaka WinSock, yang memiliki kebiasaan untuk kembali segera setelah beberapa data tiba, tetapi tidak harus semuanya . Jadi, Anda perlu memasukkan loop untuk terus meneleponselect.select()
hingga semua data diterima. Bagaimana Anda tahu bahwa Anda telah mendapatkan semua data (sayangnya) terserah Anda untuk mengetahuinya - ini mungkin berarti mencari string terminator, sejumlah byte, atau hanya menunggu waktu tunggu yang ditentukan.ready[0]
hanya salah jika tidak ada bagian dalam respons server?disana
socket.settimeout()
sumber
select
lebih disukai ketika solusi ini adalah satu liner (lebih mudah dirawat, lebih sedikit risiko dalam penerapan yang salah) dan menggunakan pilihan di bawah tenda (penerapannya sama dengan jawaban @DanielStuzbach).Seperti yang disebutkan, keduanya
select.select()
dansocket.settimeout()
akan berhasil.Perhatikan bahwa Anda mungkin perlu menelepon
settimeout
dua kali untuk kebutuhan Anda, misalnyasumber
.settimeout()
lebih dari sekali, Anda dapat memanggilsetdefaulttimeout()
metode ini sejak awal.Anda dapat menyetel batas waktu sebelum menerima respons dan setelah menerima respons, setel kembali ke Tidak Ada:
sumber
Waktu tunggu yang Anda cari adalah batas waktu soket sambungan, bukan waktu tunggu soket utama, jika Anda menerapkan sisi server. Dengan kata lain, ada waktu tunggu lain untuk objek soket sambungan, yang merupakan keluaran
socket.accept()
metode. Karena itu:Jika Anda menerapkan sisi klien, itu akan sederhana.
sumber
Seperti yang disebutkan dalam balasan sebelumnya, Anda dapat menggunakan sesuatu seperti:
.settimeout()
Misalnya:Saya harap ini membantu!!
sumber
Anda dapat menggunakan
socket.settimeout()
yang menerima argumen integer yang mewakili jumlah detik. Misalnya,socket.settimeout(1)
akan menyetel waktu tunggu ke 1 detiksumber
coba ini menggunakan C. yang mendasari.
sumber
SO_RCVTIMEO
danSO_SNDTIMEO
.2
dan mengapa100
? Berapakah nilai batas waktu? Di unit apa?timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 berarti 10 mssumber
Berteriak kepada: https://boltons.readthedocs.io/en/latest/socketutils.html
Ini menyediakan soket buffer, ini menyediakan banyak fungsi yang sangat berguna seperti:
sumber