Tôi cần đặt thời gian chờ trên phương thức recv socket của python. Làm thế nào để làm nó?
Tôi cần đặt thời gian chờ trên phương thức recv socket của python. Làm thế nào để làm nó?
Câu trả lời:
Cách tiếp cận điển hình là sử dụng select () để đợi cho đến khi dữ liệu có sẵn hoặc cho đến khi thời gian chờ xảy ra. Chỉ gọi recv()
khi dữ liệu thực sự có sẵn. Để an toàn, chúng tôi cũng đặt ổ cắm ở chế độ không chặn để đảm bảo rằng ổ cắm recv()
sẽ không bao giờ chặn vô thời hạn. select()
cũng có thể được sử dụng để chờ trên nhiều ổ cắm cùng một lúc.
import select
mysocket.setblocking(0)
ready = select.select([mysocket], [], [], timeout_in_seconds)
if ready[0]:
data = mysocket.recv(4096)
Nếu bạn có nhiều trình mô tả tệp đang mở, thì thăm dò ý kiến () là một giải pháp thay thế hiệu quả hơn select()
.
Một tùy chọn khác là đặt thời gian chờ cho tất cả các hoạt động trên ổ cắm bằng cách sử dụng socket.settimeout()
, nhưng tôi thấy rằng bạn đã từ chối giải pháp đó một cách rõ ràng trong một câu trả lời khác.
select
là tốt, nhưng phần mà bạn nói "bạn không thể" gây hiểu nhầm, vì có socket.settimeout()
.
select
- nếu bạn đang chạy trên máy Windows, hãy select
dựa vào thư viện WinSock, thư viện này có thói quen trả về ngay sau khi một số dữ liệu được gửi đến, nhưng không nhất thiết phải là tất cả . Vì vậy, bạn cần kết hợp một vòng lặp để tiếp tục gọi select.select()
cho đến khi nhận được tất cả dữ liệu. Làm thế nào bạn biết bạn đã nhận được tất cả dữ liệu (không may là) tùy thuộc vào bạn để tìm ra - nó có thể có nghĩa là tìm kiếm một chuỗi kết thúc, một số byte nhất định hoặc chỉ chờ một khoảng thời gian chờ xác định.
ready[0]
chỉ sai nếu không có phần thân trong phản hồi của máy chủ?
select
được ưu tiên khi giải pháp này là một lớp lót (dễ bảo trì hơn, ít rủi ro hơn khi triển khai sai) và sử dụng lựa chọn ẩn (cách triển khai giống như câu trả lời @DanielStuzbach).
Như đã đề cập cả hai select.select()
và socket.settimeout()
sẽ hoạt động.
Lưu ý rằng bạn có thể cần gọi settimeout
hai lần nếu cần
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()
nhiều lần, bạn có thể gọi setdefaulttimeout()
phương thức ngay từ đầu.
Thời gian chờ mà bạn đang tìm kiếm là thời gian chờ của ổ cắm kết nối không phải của ổ cắm chính, nếu bạn triển khai phía máy chủ. Nói cách khác, có một thời gian chờ khác cho đối tượng socket kết nối, đó là đầu ra của socket.accept()
phương thức. Vì thế:
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.
Nếu bạn triển khai phía khách hàng, nó sẽ đơn giản.
sock.connect(server_address)
sock.settimeout(3)
Như đã đề cập trong các câu trả lời trước, bạn có thể sử dụng một cái gì đó như: .settimeout()
Ví dụ:
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()
Tôi hi vọng cái này giúp được!!
Bạn có thể sử dụng socket.settimeout()
mà chấp nhận một đối số nguyên đại diện cho số giây. Ví dụ: socket.settimeout(1)
sẽ đặt thời gian chờ là 1 giây
hãy thử điều này, nó sử dụng C bên dưới.
timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
SO_RCVTIMEO
và SO_SNDTIMEO
.
2
và tại sao 100
? Giá trị thời gian chờ nào là? Ở đơn vị nào?
timeval = struct.pack('ll', sec, usec)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)
usec = 10000 có nghĩa là 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
Kêu to: https://boltons.readthedocs.io/en/latest/socketutils.html
Nó cung cấp một ổ cắm được đệm, điều này cung cấp rất nhiều chức năng rất hữu ích như:
.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)