अजगर के सॉकेट रिकव विधि पर टाइमआउट कैसे सेट करें?


110

मुझे अजगर के सॉकेट आरईवी विधि पर टाइमआउट सेट करने की आवश्यकता है। यह कैसे करना है?


2
FYI करें यदि आप टाइमआउट का उपयोग करना चुनते हैं ... तो आपको यह जानना होगा कि टाइमआउट को कैसे संभालना है। यह एसओ सवाल संभालता है जब एक टाइमआउट होता है: stackoverflow.com/questions/16745409
ट्रेवर बॉयड स्मिथ

जवाबों:


125

विशिष्ट दृष्टिकोण डेटा के उपलब्ध होने तक या समय समाप्त होने तक प्रतीक्षा करने के लिए चयन () का उपयोग करना है। केवल 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(), लेकिन मैं देख रहा हूं कि आपने उस समाधान को दूसरे उत्तर में स्पष्ट रूप से अस्वीकार कर दिया है।


16
उपयोग selectअच्छा है, लेकिन आप कहते हैं कि "आप नहीं कर सकते हैं" भाग भ्रामक है, क्योंकि वहाँ है socket.settimeout()
nosklo

1
अब यह बेहतर है, लेकिन मैं नहीं देखता कि उत्तर "स्पष्ट रूप से खारिज" कहां था।
nosklo

7
उपयोग करने पर एक सावधानी select- यदि आप विंडोज मशीन पर चल रहे हैं, selectतो WinSock लाइब्रेरी पर निर्भर करता है, जिसमें कुछ डेटा आते ही वापस लौटने की आदत होती है , लेकिन जरूरी नहीं कि यह सब हो। इसलिए आपको select.select()सभी डेटा प्राप्त होने तक कॉल करने के लिए एक लूप को शामिल करना होगा । आप कैसे जानते हैं कि आपने सारा डेटा प्राप्त कर लिया है (दुर्भाग्य से) यह पता लगाने के लिए - इसका मतलब हो सकता है कि आप एक टर्मिनेटर स्ट्रिंग, एक निश्चित संख्या में बाइट्स की तलाश कर रहे हैं, या बस एक निर्धारित समय के लिए प्रतीक्षा कर रहे हैं।
जेडीएम

4
सॉकेट को बिना किसी अवरोध के सेट करना क्यों आवश्यक है? मुझे नहीं लगता कि चुनिंदा कॉल के लिए यह मायने रखता है (और यह तब तक ब्लॉक होता है जब तक कि एक डिस्क्रिप्टर को नहीं पढ़ा जा सकता है या इस मामले में समय समाप्त हो जाता है) और रिकव () ब्लॉक नहीं करेगा यदि चयन संतुष्ट है। मैंने इसे recvfrom () का उपयोग करके आज़माया और यह बिना सेटब्लॉकिंग (0) के सही ढंग से काम करने लगता है।
HankB

1
चाहेंगे ready[0]केवल गलत हो अगर वहाँ सर्वर की प्रतिक्रिया में कोई शरीर है?
मटनस्टर

60

वहाँ है socket.settimeout()


16
यह recv को टाइमआउट नहीं करता (कम से कम जब मैंने इसे आज़माया)। केवल स्वीकार () का समय समाप्त हो गया है।
ओरेन एस

9
Socket.recv () मेरे लिए ठीक समय के लिए लगता है कि socket.settimeout () सेट करने के बाद ठीक है, जैसा कि इरादा था। क्या मुझसे यह व्यवस्थित हो रहा है? क्या कोई और इसकी पुष्टि कर सकता है?
अन्नौत

3
@Aeonaut मुझे लगता है कि इस बार ज्यादातर समय निकल गया (), लेकिन दौड़ की स्थिति है। सॉकेट.रेकव () में पायथन (2.6) कॉलआउट के साथ आंतरिक रूप से चुनिंदा / पोल कॉल करता है और फिर रिकव () को सही के बाद कहा जाता है। इसलिए यदि आप एक अवरुद्ध सॉकेट का उपयोग करते हैं और इन 2 के बीच दूसरे छोर बिंदु दुर्घटनाओं को कॉल करते हैं, तो आप अनिश्चित रूप से आरईवी () पर लटका सकते हैं। यदि आप गैर-अवरुद्ध सॉकेट का उपयोग करते हैं, तो अजगर आंतरिक रूप से select.select को कॉल नहीं करता है, इसलिए मुझे लगता है कि डैनियल स्टुट्ज़बाक का जवाब सही तरीका है।
emil.p.stanchev

4
वास्तव में, मैं शायद गलत समझ लेता हूं जब चयन () रिटर्न होता है, तो कृपया पिछली टिप्पणी को खरोंच दें। बीजे की गाइड का कहना है कि उपरोक्त रीव्यू पर टाइमआउट को लागू करने का एक वैध तरीका है: beej.us/guide/bgnet/output/html/singlepage/… तो मुझे विश्वास है कि यह एक आधिकारिक स्रोत है।
emil.p.stanchev

2
मुझे यकीन नहीं है कि क्यों उपयोग किए जाने वाले समाधान selectको प्राथमिकता दी जाती है जब यह समाधान एक लाइनर (आसान बनाए रखना, गलत तरीके से लागू करने में कम जोखिम) और हुड के तहत चयन का उपयोग करता है (कार्यान्वयन @DanielStuzbach उत्तर के समान है)।
ट्रेवर बोयड स्मिथ

33

जैसा कि दोनों ने उल्लेख किया है 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)

3
मुझे लगता है कि वह एक ही चीज में मुझे मिल रहा है जहां मैं कोई फर्क नहीं पड़ता कि आप इस फ़ंक्शन को कैसे प्रहार और उड़ाते हैं। मैंने अभी 2 या 4 टाइमआउट की कोशिश की है और यह अभी भी लटका हुआ है। साथ ही साथ बसना।
केसी डैनियल

1
जैसा कि आप .settimeout()एक से अधिक बार कॉल करते हैं, तो आप setdefaulttimeout()पहले स्थान पर विधि को कॉल कर सकते हैं ।
21

12

आप प्रतिक्रिया प्राप्त करने से पहले टाइमआउट सेट कर सकते हैं और प्रतिक्रिया प्राप्त करने के बाद इसे किसी को वापस सेट नहीं कर सकते हैं:

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

sock.settimeout(5.0)
data = sock.recv(1024)
sock.settimeout(None)

5

आप जिस टाइमआउट की तलाश कर रहे हैं, वह कनेक्शन सॉकेट का टाइमआउट है, न कि प्राइमरी सॉकेट का, अगर आप सर्वर साइड को लागू करते हैं। दूसरे शब्दों में, कनेक्शन सॉकेट ऑब्जेक्ट के लिए एक और टाइमआउट है, जो 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)

2

जैसा कि पिछले उत्तरों में बताया गया है, आप कुछ इस तरह उपयोग कर सकते हैं: .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()

आशा है कि ये आपकी मदद करेगा!!


2

आप socket.settimeout()सेकंड की संख्या का प्रतिनिधित्व करने वाले पूर्णांक तर्क को स्वीकार कर सकते हैं । उदाहरण के लिए, socket.settimeout(1)टाइमआउट को 1 सेकंड में सेट करेगा


2

इसे आज़माएं यह अंतर्निहित C का उपयोग करता है।

timeval = struct.pack('ll', 2, 100)
s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)

यह बहुत अच्छा है के रूप में यह भेजने और recv टाइमआउट प्रयोग करने के लिए अलग-अलग मान सेट करने के लिए एक की अनुमति देता है SO_RCVTIMEOऔर SO_SNDTIMEO
jtpereyda

क्यों 2और क्यों 100? टाइमआउट मान क्या है? किस इकाई में?
एल्फ

timeval = struct.pack('ll', sec, usec) s.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, timeval)usec = 10000 का अर्थ है 10 ms
तावी

1
#! /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

0

इसके लिए चिल्लाएँ: 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)
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.