Twisted在几乎所有方面都更好。它更便携、更丰富、更简单、更可扩展、维护更好、文档更好,而且可以制作美味煎蛋卷。Asyncore就算是过时了。
很难在短时间内展示Twisted的所有优势(我怎么能用一个简短的例子展示
http/
dns/
ssh/
smtp/pop/imap/
irc/xmpp/
process-spawning/
multi-threading服务器呢?),所以我将专注于人们似乎对Twisted有的最常见的误解之一:它比asyncore更复杂或更难使用。
让我们从一个asyncore的例子开始。为了避免偏见,我将使用来自仍然喜欢asyncore的其他人的示例。这是一个简单的asyncore示例摘自Richard Jones的博客(为了简洁起见省略了注释)。
首先,这是服务器端:
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示例也比asyncore短25%。 asyncore需要40行,而Twisted只需要30行。随着您的协议变得更加复杂,这种差异将变得越来越大,因为您需要编写越来越多的支持代码,而这些支持代码在Twisted中已经为您提供。
其次,Twisted提供了完整的抽象。使用asyncore示例,您必须使用socket
模块来执行实际的网络操作;asyncore仅提供多路复用。如果您需要在Windows等平台上具有可移植性,这将成为问题。这也意味着asyncore完全缺乏在其他平台上进行异步子进程通信的工具;您无法将任意文件描述符插入Windows上的select()
调用中。
第三,Twisted示例是传输中立的。
Echo
和
EchoFactory
和
EchoClient
和
EchoClientFactory
都不特定于TCP。 您可以将这些类制作成库,通过更改底部的一个
connectTCP
/
listenTCP
调用,仅通过SSH、SSL、UNIX套接字或管道进行连接。 这很重要,因为在协议逻辑中直接支持诸如TLS之类的内容非常棘手。例如,在TLS中的“写”会触发较低级别的“读”。 因此,您需要将这些问题分开以正确处理它们。
最后,针对您的用例,如果您直接处理MAC地址和以太网帧,则Twisted包含
Twisted Pair,这是一个用于处理IP和以太网级别网络的低级库。 这不是Twisted中最活跃的部分;代码相当古老。 但是,它应该有效,如果出现问题,我们会认真处理任何错误并(最终)确保它们得到修复。据我所知,asyncore没有可比拟的库,并且它肯定不包含任何此类代码。
accept
返回的EMFILE
或ENOMEM
,或者从recv
返回的EWOULDBLOCK
。这些情况只会在相当隐晦的条件下发生(评论长度限制将阻止我完全描述它们),但Twisted将会默默地处理它们,而asyncore
将会崩溃其主循环。 - GlyphEWOULDBLOCK
似乎是一个错误。 - schlamar