Twisted 在几乎所有可能的方面都更好。它更便携、更有特色、更简单、更具可扩展性、更好的维护、更好的文档记录,并且可以制作美味的煎蛋卷。就所有意图和目的而言,Asyncore 已经过时了。
很难在简短的回答中展示 Twisted 的所有优势(我怎么能展示 http/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/@ 987654327@ server 在一个简短的例子中?),所以我将重点关注人们似乎对 Twisted 最常见的误解之一:它比 asyncore 更复杂或更难使用。
让我们从一个异步的例子开始。为了避免有偏见的介绍,我将使用仍然有点喜欢 asyncore 的其他人的示例。这是一个简单的异步示例 taken from Richard Jones' weblog(为简洁起见,省略了 cmets)。
首先,这是服务器:
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()
我想提请您注意几件事。首先,Twisted 的例子缩短了 25%,即使是这样微不足道的东西。 asyncore 40 行,Twisted 只有 30 行。随着您的协议变得越来越复杂,这种差异会越来越大,因为您需要为 Twisted 为您提供的 asyncore 编写越来越多的支持代码。
其次,Twisted 提供了一个完整的抽象。对于 asyncore 示例,您必须使用 socket 模块来进行实际联网; asyncore 仅提供多路复用。如果您需要portable behavior on platforms such as Windows,这是一个问题。这也意味着 asyncore 完全缺乏在其他平台上进行异步子进程通信的设施;您不能将任意文件描述符填充到 Windows 上的 select() 调用中。
第三,Twisted 示例是传输中立。 Echo 和 EchoFactory 和 EchoClient 和 EchoClientFactory 都不是特定于 TCP 的。只需更改底部的 connectTCP/listenTCP 调用,您就可以将这些类变成可以通过 SSH、SSL、UNIX 套接字或管道连接的库。这很重要,因为直接在您的协议逻辑中支持诸如 TLS 之类的东西非常棘手。例如,TLS 中的“写入”将触发较低级别的“读取”。因此,您需要将这些问题分离出来以使它们正确。
最后,针对您的用例,如果您直接处理 MAC 地址和以太网帧,Twisted 包含 Twisted Pair,这是一个用于处理 IP 和以太网级网络的低级库。这不是 Twisted 中维护最积极的部分。代码很旧。但是,它应该可以工作,如果没有,我们将认真对待其中的任何错误,并(最终)看到它们得到修复。据我所知,没有可比的 asyncore 库,而且它本身当然也不包含任何此类代码。