ฉันต้องการตั้งค่าการหมดเวลาในวิธีการรับซ็อกเก็ตของ 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)