python异步处理,如何在python中的类中处理异步,而不阻塞任何内容?

I need to create a class that can receive and store SMTP messages, i.e. E-Mails. To do so, I am using asyncore according to an example posted here. However, asyncore.loop() is blocking so I cannot do anything else in the code.

So I thought of using threads. Here is an example-code that shows what I have in mind:

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()

I hope you get the picture. The class MyServer should be able to start and stop listening to port 25 in a non-blocking way, able to be queried for messages while listening (or not). The start method starts the asyncore.loop() listener, which, when a reception of an email occurs, append to an internal list. Similar, the stop method should be able to stop this server, as suggested here.

Despite the fact this code does not work as I expect to (asyncore seems to run forever, even I call the above stop method. The error I raise is catched within stop, but not within the target function containing asyncore.loop()), I am not sure if my approach to the problem is senseful. Any suggestions for fixing the above code or proposing a more solid implementation (without using third party software), are appreciated.

解决方案

The solution provided might not be the most sophisticated solution, but it works reasonable and has been tested.

First of all, the matter with asyncore.loop() is that it blocks until all asyncore channels are closed, as user Wessie pointed out in a comment before. Referring to the smtp example mentioned earlier, it turns out that smtpd.SMTPServer inherits from asyncore.dispatcher (as described on the smtpd documentation), which answers the question of which channel to be closed.

Therefore, the original question can be answered with the following updated example code:

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

....

So in the end, I have a start and a stop method to start and stop listening on port 25 within a non-blocking environment.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值