我正在制作一个程序,它将同时从两个“网络资源”中读取。我想尝试一种异步方法,而不是使用线程。这让我想知道使用哪个库...
我想出了一些简单的示例代码,它可以演示我的程序将要执行的操作:
import sniffer
def first():
for station in sniffer.sniff_wifi():
log(station.mac())
def second():
for station in sniffer.sniff_ethernet():
log(station.mac())
first()
second()
两个sniffer
方法看起来像这样:
def sniff_wifi(self):
while True:
yield mac_address
while True
循环显然会阻止它们。
我想使用asyncore
,因为它是标准库的一部分。没有第三方依赖是奖金。但是,如果你建议我这样做,那并不意味着我不会使用它......
我可以实现我想用asyncore做的事情吗?如果是这样,你能告诉我如何将我的示例代码转换为'asyncore代码'吗?你知道任何好的asyncore教程吗?
答案 0 :(得分:50)
Twisted在几乎所有方面都更好。它更便携,更功能,更简单,更具可扩展性,更好的维护,更好的文档记录,它可以制作美味的煎蛋卷。无论如何,Asyncore已经过时了。
很难在短答案中展示Twisted优越的所有方式(我如何演示http / dns / ssh / smtp/pop/imap / { {3}} / irc/xmpp / process-spawning服务器在一个简短的例子中?),所以我将集中讨论人们似乎对Twisted的一个最常见的误解:它在某种程度上更复杂或者比asyncore更难使用。
让我们从asyncore示例开始。为了避免有偏见的演示,我将使用其他人仍然喜欢asyncore的例子。这是一个简单的异步核心示例multi-threading(由于简洁而省略了注释)。
首先,这是服务器:
import asyncore, socket
class Server(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(1)
def handle_accept(self):
socket, address = self.accept()
print 'Connection by', address
EchoHandler(socket)
class EchoHandler(asyncore.dispatcher_with_send):
def handle_read(self):
self.out_buffer = self.recv(1024)
if not self.out_buffer:
self.close()
s = Server('', 5007)
asyncore.loop()
这是客户:
import asyncore, socket
class Client(asyncore.dispatcher_with_send):
def __init__(self, host, port, message):
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
self.out_buffer = message
def handle_close(self):
self.close()
def handle_read(self):
print 'Received', self.recv(1024)
self.close()
c = Client('', 5007, 'Hello, world')
asyncore.loop()
有一些模糊的情况,这些代码无法正确处理,但解释它们是无聊和复杂的,代码已经使这个答案足够长。
现在,这里有一些基本相同的代码,使用Twisted。首先,服务器:
from twisted.internet import reactor, protocol as p
class Echo(p.Protocol):
def dataReceived(self, data):
self.transport.write(data)
class EchoFactory(p.Factory):
def buildProtocol(self, addr):
print 'Connection by', addr
return Echo()
reactor.listenTCP(5007, EchoFactory())
reactor.run()
现在,客户:
from twisted.internet import reactor, protocol as p
class EchoClient(p.Protocol):
def connectionMade(self):
self.transport.write(self.factory.data)
def dataReceived(self, data):
print 'Received:', data
self.transport.loseConnection()
class EchoClientFactory(p.ClientFactory):
protocol = EchoClient
def __init__(self, data):
self.data = data
reactor.connectTCP('localhost', 5007, EchoClientFactory('Hello, world'))
reactor.run()
有几件事我想引起你的注意。首先,扭曲的例子缩短了25%,即使对于这个微不足道的事情也是如此。 asyncore有40行,Twisted只有30行。随着协议变得越来越复杂,这种差异将越来越大,因为您需要为Twisted提供的asyncore编写越来越多的支持代码。
其次,Twisted提供了完全抽象。使用asyncore示例,您必须使用socket
模块来进行实际的网络连接; asyncore仅提供多路复用。如果您需要taken from Richard Jones' weblog,这是一个问题。这也意味着asyncore完全缺乏在其他平台上进行异步子进程通信的工具;你不能将任意文件描述符填充到Windows上的select()
调用中。
第三,Twisted示例是传输中立。 Echo
和EchoFactory
以及EchoClient
和EchoClientFactory
都不是TCP特有的。您可以将这些类放入可通过SSH,SSL或UNIX套接字或管道连接的库中,只需更改底部的connectTCP
/ listenTCP
调用即可。这很重要,因为在协议逻辑中直接支持TLS之类的东西非常棘手。例如,TLS中的“写入”将触发较低级别的“读取”。因此,您需要将这些问题分开,以使其正确。
最后,具体到您的用例,如果您直接处理MAC地址和以太网帧,Twisted包含portable behavior on platforms such as Windows,一个用于处理IP和以太网级网络的低级库。这不是Twisted中最积极维护的部分;代码很旧。但是,它应该有效,如果不成功,我们会认真对待任何错误,并(最终)看到它们得到修复。据我所知,asyncore没有类似的库,它当然不包含任何此类代码。
答案 1 :(得分:3)
Asyncore很好但功能不是很丰富,所以当你的应用程序增长时,你可能会遇到问题。话虽如此,原型设计很棒。方法很简单。您可以定义处理类中某些事件的方法(当可以读取时,可以写入时等),然后从asyncore.dispatcher(我认为)类中继承它们。
official docs for the module以及Doug Hellmann优秀的PyMOTW article on it是查看文档和示例的良好来源。
如果您的协议是会话式的(例如发送,接收),您可以查看asynchat模块,该模块也随标准库一起分发。
Twisted是一种更加繁重的方法。我相信它对于大型项目会更好,因为它使用了多少,但我不能再多说了,因为我没有任何第一手经验。
答案 2 :(得分:0)
Curl被设计为在所有视角中都是非阻塞的,并且避免使用select,这在异步I / O期间是一项代价高昂的操作。在低级别,curl正在使用最优化的可能解决方案,因此到目前为止没有框架能够比卷曲更好地执行,尽管可能存在可以提供类似性能的框架。
话虽如此,如何编写自己的套接字?它非常容易使用Python,一旦你知道自己在做什么就可以给你惊人的表现,而且你的目标很明确。