ฉันต้องการตั้งค่าการหมดเวลาในวิธีการรับซ็อกเก็ตของ python ทำอย่างไร?
ฉันต้องการตั้งค่าการหมดเวลาในวิธีการรับซ็อกเก็ตของ python ทำอย่างไร?
คำตอบ:
แนวทางโดยทั่วไปคือใช้select ()เพื่อรอจนกว่าข้อมูลจะพร้อมใช้งานหรือจนกว่าจะหมดเวลา โทรrecv()
เมื่อมีข้อมูลจริงเท่านั้น เพื่อความปลอดภัยเรายังตั้งค่าซ็อกเก็ตเป็นโหมดไม่ปิดกั้นเพื่อรับประกันว่าrecv()
จะไม่มีการปิดกั้นอย่างไม่มีกำหนด select()
ยังสามารถใช้เพื่อรอมากกว่าหนึ่งซ็อกเก็ตในแต่ละครั้ง
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
หากคุณมีตัวอธิบายไฟล์ที่เปิดอยู่จำนวนมากแบบสำรวจ ()เป็นทางเลือกที่มีประสิทธิภาพมากกว่าสำหรับselect()
ไฟล์.
อีกทางเลือกหนึ่งคือกำหนดระยะหมดเวลาสำหรับการดำเนินการทั้งหมดบนซ็อกเก็ตโดยใช้socket.settimeout()
แต่ฉันเห็นว่าคุณได้ปฏิเสธโซลูชันนั้นอย่างชัดเจนในคำตอบอื่น
select
เป็นสิ่งที่ดี แต่เป็นส่วนหนึ่งที่คุณพูดว่า "คุณไม่สามารถ" socket.settimeout()
เป็นความเข้าใจผิดเนื่องจากมี
select
- ถ้าคุณกำลังทำงานอยู่บนเครื่อง Windows select
อาศัยห้องสมุด WinSock ซึ่งมีนิสัยของการกลับมาให้เร็วที่สุดเท่าบางข้อมูลที่ได้มาถึง แต่ไม่จำเป็นต้องทั้งหมดของมัน ดังนั้นคุณต้องรวมลูปเพื่อโทรselect.select()
ต่อไปจนกว่าจะได้รับข้อมูลทั้งหมด วิธีที่คุณรู้ว่าคุณได้รับข้อมูลทั้งหมดนั้น (น่าเสียดาย) ขึ้นอยู่กับคุณที่จะคิดออก - อาจหมายถึงการมองหาสตริงเทอร์มิเนเตอร์จำนวนไบต์ที่กำหนดหรือรอการหมดเวลาที่กำหนด
ready[0]
เป็นเท็จก็ต่อเมื่อไม่มีเนื้อหาในการตอบสนองของเซิร์ฟเวอร์?
select
จึงเป็นที่ต้องการเมื่อโซลูชันนี้เป็นแบบซับเดียว (ดูแลรักษาง่ายกว่ามีความเสี่ยงน้อยกว่าในการใช้งานผิดพลาด) และใช้การเลือกภายใต้ประทุน (การใช้งานเหมือนกับคำตอบของ @DanielStuzbach)
ดังกล่าวทั้งสองselect.select()
และsocket.settimeout()
จะทำงาน
โปรดทราบว่าคุณอาจต้องโทรsettimeout
สองครั้งตามความต้องการของคุณเช่น
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.bind(("",0))
sock.listen(1)
# accept can throw socket.timeout
sock.settimeout(5.0)
conn, addr = sock.accept()
# recv can throw socket.timeout
conn.settimeout(5.0)
conn.recv(1024)
.settimeout()
มากกว่าหนึ่งครั้งคุณสามารถเรียกใช้setdefaulttimeout()
เมธอดได้ตั้งแต่แรก
คุณสามารถตั้งค่าการหมดเวลาก่อนได้รับการตอบกลับและหลังจากได้รับการตอบกลับแล้วให้ตั้งค่ากลับเป็นไม่มี:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)
การหมดเวลาที่คุณกำลังมองหาคือการหมดเวลาของซ็อกเก็ตการเชื่อมต่อไม่ใช่ซ็อกเก็ตหลักหากคุณใช้ฝั่งเซิร์ฟเวอร์ กล่าวอีกนัยหนึ่งมีการหมดเวลาอื่นสำหรับอ็อบเจ็กต์ซ็อกเก็ตการเชื่อมต่อซึ่งเป็นเอาต์พุตของsocket.accept()
วิธีการ ดังนั้น:
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.
หากคุณใช้งานฝั่งไคลเอ็นต์มันจะง่ายมาก
sock.connect(server_address)
sock.settimeout(3)
ดังที่ได้กล่าวไว้ในคำตอบก่อนหน้านี้คุณสามารถใช้สิ่งต่างๆ.settimeout()
เช่น:
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 bytes
except socket.timeout: # fail after 1 second of no activity
print("Didn't receive data! [Timeout]")
finally:
s.close()
ฉันหวังว่านี่จะช่วยได้!!
คุณสามารถใช้socket.settimeout()
ซึ่งยอมรับอาร์กิวเมนต์จำนวนเต็มแทนจำนวนวินาที ตัวอย่างเช่นsocket.settimeout(1)
จะตั้งค่าการหมดเวลาเป็น 1 วินาที
ลองใช้มันใช้พื้นฐาน C.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
SO_SNDTIMEO
2
และทำไม100
? ค่าการหมดเวลาคืออะไร? อยู่ในหน่วยใด?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 หมายถึง 10 ms
#! /usr/bin/python3.6
# -*- coding: utf-8 -*-
import socket
import time
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.settimeout(5)
PORT = 10801
s.bind(('', PORT))
print('Listening for broadcast at ', s.getsockname())
BUFFER_SIZE = 4096
while True:
try:
data, address = s.recvfrom(BUFFER_SIZE)
except socket.timeout:
print("Didn't receive data! [Timeout 5s]")
continue
ติดต่อไปที่: https://boltons.readthedocs.io/en/latest/socketutils.html
มีซ็อกเก็ตบัฟเฟอร์ซึ่งมีฟังก์ชันการทำงานที่มีประโยชน์มากมายเช่น:
.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)