2013-01-23 38 views
10

मुझे ऐसी कक्षा बनाने की आवश्यकता है जो एसएमटीपी संदेशों को प्राप्त और स्टोर कर सके, यानी ई-मेल। ऐसा करने के लिए, here पोस्ट किए गए उदाहरण के अनुसार, मैं asyncore का उपयोग कर रहा हूं। हालांकि, asyncore.loop() अवरुद्ध है इसलिए मैं कोड में और कुछ नहीं कर सकता।कुछ भी अवरुद्ध किए बिना, अजगर में एक वर्ग के भीतर asyncore को कैसे संभालें?

तो मैंने धागे का उपयोग करने के बारे में सोचा। यहाँ एक उदाहरण-कोड पता चलता है कि मेरे मन में है:

class MyServer(smtpd.SMTPServer): 
    # derive from the python server class 

    def process_message(..): 
     # overwrite a smtpd.SMTPServer method to be able to handle the received messages 
     ... 
     self.list_emails.append(this_email) 

    def get_number_received_emails(self): 
     """Return the current number of stored emails""" 
     return len(self.list_emails) 


    def start_receiving(self): 
     """Start the actual server to listen on port 25""" 

     self.thread = threading.Thread(target=asyncore.loop) 
     self.thread.start()  

    def stop(self): 
     """Stop listening now to port 25""" 
     # close the SMTPserver from itself 
     self.close() 
     self.thread.join() 

मुझे आशा है कि आप चित्र मिलता है। कक्षा MyServer गैर-अवरुद्ध तरीके से बंदरगाह 25 को सुनने और बंद करने में सक्षम होना चाहिए, सुनने के दौरान संदेशों के लिए पूछताछ करने में सक्षम होना चाहिए (या नहीं)। start विधि asyncore.loop() श्रोता शुरू करती है, जो, जब कोई ईमेल प्राप्त होता है, तो आंतरिक सूची में शामिल होता है। इसी तरह, stop विधि इस सर्वर को रोकने में सक्षम होना चाहिए, जैसा कि here सुझाया गया है।

तथ्य के रूप में मैं उम्मीद इस कोड काम नहीं करता है के बावजूद करने के लिए (asyncore हमेशा के लिए चलाने के लिए मैं भी ऊपर stop विधि कॉल लगता है,। error मैं बढ़ा stop भीतर catched है, लेकिन asyncore.loop() युक्त target समारोह के भीतर नहीं), मुझे यकीन नहीं है कि समस्या का मेरा दृष्टिकोण समझदार है या नहीं। उपर्युक्त कोड को ठीक करने या तीसरे पक्ष के सॉफ़्टवेयर का उपयोग करके के बिना अधिक ठोस कार्यान्वयन () का प्रस्ताव देने के लिए कोई सुझाव, की सराहना की जाती है।

+0

मुझे कुछ भ्रम लगता है। 'Asyncore.loop()' अवरुद्ध करने में समस्या क्या है? क्या आप समझते हैं कि आप 'लूप' फ़ंक्शन क्यों कहते हैं और यह क्या करता है? – mmgp

+0

@mmgp: 'asyncore.loop()' के साथ समस्या यह है कि यह अवरुद्ध है।मैं किसी अन्य समय किसी भी समय कक्षा का उपयोग करने में सक्षम होना चाहता हूं। दूसरी तरफ, मैं 'asyncore.loop()' पर एक विशेषज्ञ नहीं हूं, लेकिन AFAIK यह आंतरिक 'select.select' को आंतरिक करता है, जो दिख रहा है उदा। इस मामले में पोर्ट 25 पर आने वाले एसएमटीपी संदेशों के लिए। – Alex

+0

क्या आपने GUI टूलकिट का उपयोग किया है? असल में वे सभी घटना loops पर आधारित हैं। आपको चीजें व्यवस्थित करने की ज़रूरत है कि वे "ईवेंट लूप" द्वारा प्रबंधित किए जाने वाले ईवेंट तैयार करें। मैंने जो भ्रम का उल्लेख किया है वह इसलिए है क्योंकि आप किसी घटना लूप का उपयोग करने के बारे में अनजान प्रतीत होते हैं, क्या यह मामला है? – mmgp

उत्तर

12

प्रदान किया गया समाधान सबसे परिष्कृत समाधान नहीं हो सकता है, लेकिन यह उचित काम करता है और परीक्षण किया गया है।

सबसे पहले, asyncore.loop() साथ बात है कि यह सब asyncore चैनलों तक ब्लॉक उपयोगकर्ता Wessie से पहले एक टिप्पणी में कहा के रूप में बंद हो जाती हैं, है। smtp example का जिक्र करते हुए, यह पता चला है कि smtpd.SMTPServerasyncore.dispatcher से प्राप्त होता है (जैसा कि smtpd documentation पर वर्णित है), जो कि किस चैनल को बंद करने के सवाल का उत्तर देता है।

इसलिए, मूल प्रश्न निम्नलिखित अद्यतन उदाहरण कोड के साथ उत्तर दिया जा सकता है:

class CustomSMTPServer(smtpd.SMTPServer): 
    # store the emails in any form inside the custom SMTP server 
    emails = [] 
    # overwrite the method that is used to process the received 
    # emails, putting them into self.emails for example 
    def process_message(self, peer, mailfrom, rcpttos, data): 
     # email processing 


class MyReceiver(object): 
    def start(self): 
     """Start the listening service""" 
     # here I create an instance of the SMTP server, derived from asyncore.dispatcher 
     self.smtp = CustomSMTPServer(('0.0.0.0', 25), None) 
     # and here I also start the asyncore loop, listening for SMTP connection, within a thread 
     # timeout parameter is important, otherwise code will block 30 seconds after the smtp channel has been closed 
     self.thread = threading.Thread(target=asyncore.loop,kwargs = {'timeout':1}) 
     self.thread.start()  

    def stop(self): 
     """Stop listening now to port 25""" 
     # close the SMTPserver to ensure no channels connect to asyncore 
     self.smtp.close() 
     # now it is save to wait for the thread to finish, i.e. for asyncore.loop() to exit 
     self.thread.join() 

    # now it finally it is possible to use an instance of this class to check for emails or whatever in a non-blocking way 
    def count(self): 
     """Return the number of emails received""" 
     return len(self.smtp.emails)   
    def get(self): 
     """Return all emails received so far""" 
     return self.smtp.emails 
    .... 
अंत में

तो, मैं शुरू करने और पोर्ट 25 पर सुन एक गैर भीतर रोकने के लिए एक start और एक stop विधि है पर्यावरण को अवरुद्ध करना

+1

धागे का उपयोग किये बिना ऐसा करने का कोई तरीका है? – Vikram

2

आपको इसके बजाय ट्विस्ट का उपयोग करने पर विचार करना चाहिए। http://twistedmatrix.com/trac/browser/trunk/doc/mail/examples/emailserver.tac दर्शाता है कि एक अनुकूलन योग्य ऑन-डिलीवरी हुक के साथ एक एसएमटीपी सर्वर कैसे स्थापित करें।

+2

क्षमा करें, मैं कुछ अतिरिक्त उपयोग नहीं करना चाहता हूं। मुझे और स्पष्ट होना चाहिए था। – Alex

+1

ऐसा नहीं है कि कुछ "अतिरिक्त" का उपयोग करने से वास्तव में आपकी परियोजना को नुकसान पहुंचाएगा। यह बहुत अधिक संभावना है कि यह इसे बहुत बेहतर बना देगा। आप पहले ही पाइथन का उपयोग कर रहे हैं, यह भी "अतिरिक्त" है। ठीक है, लोग सॉफ्टवेयर स्थापित कर सकते हैं। आप उनके लिए इसे स्थापित करने के लिए सुपर स्लिम पैकेज भी बना सकते हैं। पाइथन मानक पुस्तकालय में जो कुछ भी है, उसे सीमित करके, आप अविश्वसनीय रूप से उपयोगी कार्यक्षमता का भारी मात्रा में कटौती कर रहे हैं, इसका मुकाबला सिर्फ एक छोटा सा उदाहरण है। अंत में, आप अपना समय बर्बाद कर रहे हैं (और उन लोगों का समय जो आपके सवालों का जवाब देना चुनते हैं) और अपनी परियोजना को चोट पहुंचाते हैं। –

4

अन्य प्रश्न asyncore.loop doesn't terminate when there are no more connections

मुझे लगता है कि आप सूत्रण सोच से थोड़ा हैं से आ रहा है।

import threading 

loop_thread = threading.Thread(target=asyncore.loop, name="Asyncore Loop") 
# If you want to make the thread a daemon 
# loop_thread.daemon = True 
loop_thread.start() 

यह एक नया सूत्र में यह चलेंगे और जब तक सब asyncore चैनलों बंद हो जाती हैं चलती रहेगी: अन्य सवाल से कोड का उपयोग करना, आप एक नया धागा है कि निम्नलिखित कोड का टुकड़ा द्वारा asyncore.loop चलाता है शुरू कर सकते हैं।

+1

ठीक है, मैं मान रहा था कि मेरा दृष्टिकोण थोड़ा बड़ा था। लेकिन अनुवर्ती करने के लिए, इस धागे को समाप्त करने के लिए मुझे सभी 'asyncore' चैनल बंद करने की आवश्यकता है। उसको कैसे करे? मैं एसिंककोर कैसे रोक सकता हूं? मैं इस धागे को कैसे रोक सकता हूं? (मेरे वास्तविक प्रश्न के हिस्से के रूप में) – Alex

+0

@Alex सभी 'asyncore' चैनल बंद होने पर 'asyncore.loop' को कॉल अनब्लॉक कर देगा। इस संदर्भ में चैनल 'asyncore.dispatcher' या' asynchat.async_chat' के किसी उप-वर्गों का जिक्र करते हैं। आपके मामले में आपको उस समय 'server.close()' को कॉल करने की आवश्यकता होती है जब आप बाहर निकलना चाहते हैं। – Wessie

+0

मैंने उपर्युक्त उदाहरण कोड में कोशिश की और 'स्टॉप' विधि में निम्नलिखित में डाल दिया: 'self.close(); self._thread.join() '। यह काम नहीं करता। यह 'thread.join' पर लटका हुआ है जिसका अर्थ है कि एक और (?) चैनल खुला है? कौनसा? उन्हें कैसे ढूंढें? – Alex