2012-12-07 15 views
6
में
open_sockets = [] 

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

listening_socket.bind(("", 1234)) 

listening_socket.listen(5) 

while True: 
    rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 
    for i in rlist: 
     if i is listening_socket: 
      new_socket, addr = listening_socket.accept() 
      open_sockets.append(new_socket) 
     else: 
      data = i.recv(1024) 
      if data == "": 
       i.close() 
       open_sockets.remove(i) 
       print "Connection closed" 
      else: 
       i.send(data) 
       print repr(data) 

अब मैं यह जानता हूँ सरल सर्वर कोड है कि कुछ ग्राहकों को संभाल कर सकते हैं कर रहा है - केवल बात यह है कि मुझे समझ नहीं आता इन दो पंक्तियों हैं:recv() अजगर

 data = i.recv(1024) 
     if data == "": 

मैं समझता हूँ कि जब ग्राहक पहले ही स्वीकार कर चुका है तो यह दूसरे विकल्प पर जायेगा, विकल्प जो चेक करता है कि बफर में कुछ है या नहीं। मुझे समझ नहीं आया क्यों, कब बफर में कुछ भी नहीं है वहाँ, उस पर चला जाता है और लाइन की जांच नहीं करता:

if data == "": 

लेकिन जब ग्राहक सिर्फ प्रेस दर्ज करें, जिनके "" के बराबर यह डिस्कनेक्ट

है

क्यों कुछ भी दबाया नहीं जाता है यह "" जैसा नहीं है?

+0

जब तक रहो अगर किसी भी प्रदान किए गए किसी ने आपके प्रश्न का उत्तर दिया है तो उत्तर स्वीकार करना सुनिश्चित करें। इस साइट पर योगदान करने वाले लोगों का धन्यवाद करने का यह एक अच्छा तरीका है। अगर आपके प्रश्न का उत्तर नहीं दिया गया है, तो हमेशा टिप्पणी करने में संकोच न करें। धन्यवाद! – GargantuChet

उत्तर

6

यह select कॉल से शुरू होता है। यह फ़ंक्शन सॉकेट सेट करता है और ऐसा होने के लिए कुछ उल्लेखनीय प्रतीक्षा करता है। पहली सूची में सॉकेट के लिए, "ध्यान देने योग्य" का अर्थ है कि सॉकेट में पढ़ने के लिए डेटा उपलब्ध है।

rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 

कोड अब पढ़ने के लिए तैयार डेटा, और कृत्यों सॉकेट के प्रकार के आधार के साथ सॉकेट की सूची के माध्यम से iterates संभाला जा रहा।

for i in rlist: 
     if i is listening_socket: 

कनेक्शन-उन्मुख ("सुनना") सॉकेट का उपयोग नए कनेक्शन को स्वीकार करने के लिए किया जाता है। चूंकि यह rlist में है, हम जानते हैं कि हमारे पास "पढ़ने" के लिए कुछ है। एक सुनवाई सॉकेट के संदर्भ में, इसका मतलब है कि एक नया कनेक्शन प्राप्त हुआ है। इसलिए हम कनेक्शन स्वीकार करते हैं, और open_sockets की सूची में नई सॉकेट को सहेजते हैं।

  new_socket, addr = listening_socket.accept() 
      open_sockets.append(new_socket) 

सॉकेट नहीं listening_socket है, तो यह एक सॉकेट जो है (या था) किसी दूरस्थ क्लाइंट से जुड़ा है। और फिर से यह rlist में है, हम जानते हैं कि हमारे पास "पढ़ने" के लिए कुछ है। कनेक्टेड सॉकेट के संदर्भ में, इसका मतलब है कि डेटा वास्तव में पढ़ने के लिए उपलब्ध है, या सॉकेट बंद कर दिया गया है।

तो हम recv फोन किसी भी उपलब्ध डेटा,

 else: 
      data = i.recv(1024) 

हो और अगर हम वास्तव में कुछ भी पढ़ा है देखने के लिए। यदि कोई डेटा उपलब्ध नहीं था, तो कनेक्शन बंद होना चाहिए, इसलिए हम सॉकेट ऑब्जेक्ट को बंद करते हैं और open_sockets से इसे हटा देते हैं।

  if data == "": 
       i.close() 
       open_sockets.remove(i) 
       print "Connection closed" 

यदि हमें वास्तव में डेटा प्राप्त होता है, तो हम इसे वापस ग्राहक को लिखते हैं और स्क्रीन पर प्रिंट करते हैं।

  else: 
       i.send(data) 
       print repr(data) 

select करने के लिए पहली कॉल जब तक एक कनेक्शन प्राप्त होता है इंतजार करेंगे।आप के रूप में

print "About to call select" 
rlist, wlist, xlist = select.select([listening_socket] + open_sockets, [], []) 
print "Returned from select" 

खुद के लिए देख सकते हैं कोड अपडेट करके पहली कॉल करने के बाद, rlistlistening_socket शामिल होंगे। हम इसे जानते हैं क्योंकि open_sockets खाली है, और select कहा जाता है जब तक कि कुछ पढ़ा नहीं जाता है तब तक वापस नहीं आ जाएगा। इसलिए हम नए कनेक्शन को स्वीकार करते हैं और इसे open_sockets में जोड़ते हैं।

जब select फिर से कहा जाता है, तो तीन संभावित घटनाएं होती हैं। सबसे पहले, listening_socket शायद एक और कनेक्शन प्राप्त हो सकता है। इस मामले में इसे पहले के रूप में संभाला जाता है: हम कनेक्शन स्वीकार करते हैं और इसे open_sockets में जोड़ते हैं।

दूसरा, नया कनेक्शन डेटा प्राप्त कर सकता था। चूंकि select ने इसे rlist में शामिल किया है, इसलिए हम जानते हैं कि डेटा सॉकेट से "पढ़ने" के लिए तैयार है (जिसका अर्थ है कि डेटा पढ़ने के लिए तैयार है, या सॉकेट बंद कर दिया गया है)। i.recv नया डेटा लौटाएगा।

तीसरा, नया कनेक्शन बंद हो सकता था। चूंकि select ने इसे rlist में शामिल किया है, इसलिए हम जानते हैं कि डेटा सॉकेट से पढ़ने के लिए तैयार है (ऊपर जैसा ही अर्थ है)। लेकिन i.recv वापस आ जाएगा क्योंकि सॉकेट में कोई नया डेटा नहीं है। तो हम जानते हैं कि सॉकेट बंद कर दिया गया है, और तदनुसार साफ करें।

यदि क्लाइंट से कोई डेटा नहीं भेजा गया है (और कनेक्शन अभी भी खुला है), तो select इसमें rlist में शामिल नहीं होगा। तो लूप इसे संसाधित नहीं करेगा, और i.recv उस विशेष सॉकेट पर नहीं बुलाया जाएगा।

+0

'socket.setblocking()' और 'socket.settimeout()' का उल्लेख करने के लायक है, मुझे लगता है, क्योंकि यह सख्ती से सच नहीं है कि 'recv' सार्वभौमिक रूप से अवरुद्ध होगा। –

+0

यह ब्लॉक नहीं करेगा। 'मैं रैलिस्ट में' कहता हूं 'मैं' पढ़ने के लिए "तैयार" हूं। 1024 bufsize है, recv() कम बाइट्स – jfs

+0

वापस कर सकता है मैंने समझने से नहीं छोड़ा था। आपने जो कहा है वह है कि अगर कुछ भी दबाया नहीं जाता है तो यह लाइन को पास नहीं करेगा, इसलिए यह अटक जाएगा और दूसरे क्लाइंट के माध्यम से नहीं मिलेगा या आपका मतलब है कि यह होगा अगर हालत छोड़ दो? – user1779374

3

जब कोई सॉकेट प्रतिक्रिया में "" भेजता है, तो आम तौर पर इसका मतलब है कि सॉकेट बंद है (या बंद करें?)। अगर मैं यहां गलत हूं तो कोई मुझे सही करेगा। उस कथन के बिना, अगर रिमोट सर्वर अचानक प्रत्युत्तर देना बंद कर देता है तो यह अनंत लूप में पकड़ा जा सकता है।

+0

यह सही है। यह सिर्फ मेरे साथ हुआ और यह एक बड़ी मेमोरी ओवरलोड बीसी पैदा कर रहा था, मैं एक टर्मिनल मार्कर की तलाश में एक सूची में डेटा जोड़ रहा था। इस पर ध्यान दिलाने के लिए धन्यवाद। –

+0

@MichaelDavidWatson एक काफी लोकप्रिय नेटवर्किंग लाइब्रेरी में एक समान बग था, और यह मेरे कोड में भ्रमित अनंत-लूप लटक रहा था। एक सरल 'यदि डेटा नहीं है: अपवाद बढ़ाएं' आमतौर पर सबसे अच्छा तय होता है। – Anorov

0

i (Btw, एक सॉकेट के लिए एक दुर्भाग्यपूर्ण नाम) rlist में नहीं होगा जब तक कि वहाँ अर्थात को पढ़ने के लिए कुछ न कुछ है, i.recv(1024)कुछ वापस आ जाएगी या कनेक्शन जैसे कि, i.recv(1024) रिटर्न b"" किया जाता है।

एक बार .recv()b"" लौटा, आपको इस सॉकेट से कुछ भी प्राप्त नहीं होगा।

"क्लाइंट (एक इंसान) की व्याख्या सिर्फ" एंटर दबाती है "क्लाइंट (सॉफ्टवेयर) पर निर्भर करती है। यह सर्वर जैसे के साथ क्या करना, ग्राहक इनपुट तार बफ़र कर सकते हैं कुछ भी नहीं है एक नई पंक्ति का सामना करना पड़ा है या टाइमआउट हुआ है या यह जैसे ही यह एक उपयोगकर्ता से यह प्राप्त करता है प्रत्येक बाइट भेज सकते हैं, आदि

-1
[[email protected] ]# grep "banner_timeout = " /opt/panel-migrator/thirdparties/python/lib/python2.7/site-packages/paramiko/transport.py 

self.banner_timeout = 60  # how long (seconds) to wait for the SSH banner