Витая лучше во всех отношениях.Это более портативный, более функциональный, простой, более масштабируемый, лучше обслуживаемый, лучше документированный, и он может сделать вкусный омлет.Asyncore, для всех намерений и целей, устарел.
Трудно продемонстрировать все способы, которыми Twisted превосходит в коротком ответе (как я мог продемонстрировать http / * 1006 DNS * / SSH / SMTP / POP / IMAP / ИРЦ / XMPP / процесс-нерестовый / мульти-в качестве примера рассмотрим сервер в кратком примере?), поэтому вместо этого я остановлюсь на одном из самых распространенных заблуждений, которые, как кажется, имеют люди в отношении Twisted: его использование сложнее или сложнее, чем asyncore.
Давайте начнем с асинхронного примера.Чтобы избежать предвзятого представления, я буду использовать пример от кого-то еще, кто все еще любит асинкоры.Вот простой асинхронный пример , взятый из блога Ричарда Джонса (с краткими комментариями, опущенными).
Во-первых, вот сервер:
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% короче, даже для чего-то такого тривиального.40 строк для Asyncore, только 30 для Twisted.По мере усложнения вашего протокола это различие будет становиться все больше и больше, так как вам нужно будет писать все больше и больше кода поддержки асинхронности, который был бы предоставлен вам Twisted.
Во-вторых, Twisted предоставляет полная абстракция .В примере asyncore вы должны использовать модуль socket
для создания реальной сети;Asyncore обеспечивает только мультиплексирование.Это проблема, если вам нужно портативное поведение на платформах, таких как Windows .Это также означает, что у asyncore полностью отсутствуют средства для асинхронного взаимодействия подпроцесса на других платформах;Вы не можете вставить произвольные файловые дескрипторы в вызов select()
в Windows.
В-третьих, пример Twisted является транспортно-нейтральным .Ни один из Echo
и EchoFactory
и EchoClient
и EchoClientFactory
не имеет никакого отношения к TCP.Вы можете превратить эти классы в библиотеку, которая может быть подключена через SSH, SSL или сокет UNIX, или канал, только изменив один вызов connectTCP
/ listenTCP
внизу.Это важно, так как поддерживать что-то вроде TLS непосредственно в логике вашего протокола очень сложно.Например, «запись» в TLS вызовет «чтение» на нижнем уровне.Таким образом, вам нужно разделить эти проблемы, чтобы разобраться в них.
Наконец, в зависимости от вашего варианта использования, если вы имеете дело с MAC-адресами и сетевыми фреймами напрямую, Twisted содержит Twisted Pair , низкоуровневая библиотека для работы с IP и сетями уровня Ethernet.Это не самая активно поддерживаемая часть Twisted;код довольно старый.Но это должно сработать, и если этого не произойдет, мы серьезно отнесемся к ошибкам и (в конце концов) увидим, что они исправлены.Насколько я знаю, нет никакой сопоставимой библиотеки для asyncore, и она, конечно же, сама не содержит такого кода.