ツイストは、可能な限りあらゆる点で優れています。より移植性が高く、機能が豊富で、シンプルでスケーラブルで、メンテナンス性が高く、文書化が容易で、美味しいオムレツを作ることができます。 Asyncoreは、すべての目的と目的のために、時代遅れです。
それはツイストは(私は短い例でhttp/dns/ssh/smtp/pop/imap/irc/xmpp/process-spawning/multi-threadingサーバーを発揮できるか?)短い答えに優れているすべての方法を実証するのは難しいので、代わりにI人々がTwistedについて持っているように見える最も一般的な誤解の1つに焦点を当てます。これは、asyncoreよりも幾分複雑で使いにくいものです。
まず、asyncoreの例を見てみましょう。偏ったプレゼンテーションを避けるために、私はまだasyncoreを少し好きな人からの例を使用します。単純な非同期の例taken from Richard Jones' weblog(簡潔にするためコメントは省略されています)があります。
まず、ここでは、サーバーの:
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のサポートコードをもっと書く必要があるので、この違いはますます大きくなります。
第2に、Twistedは、完全抽象を提供します。 asyncoreの例では、実際のネットワーキングにはsocket
モジュールを使用する必要があります。 asyncoreは多重化のみを提供します。これは、portable behavior on platforms such as Windowsが必要な場合に問題になります。また、asyncoreには、他のプラットフォーム上で非同期サブプロセス通信を行うための機能が完全にないことも意味します。任意のファイル記述子をWindowsのselect()
呼び出しに埋め込むことはできません。
第3に、ツイストの例は、輸送ニュートラルです。 Echo
とEchoFactory
とEchoClient
とEchoClientFactory
のいずれもTCPに特有のものではありません。これらのクラスは、SSHまたはSSL、UNIXソケット、またはパイプを介して接続できるライブラリにすることができます。その場合は、connectTCP
/listenTCP
コールを一番下に変更します。これは重要です。あなたのプロトコルロジックで直接TLSのようなものをサポートすることは非常に難しいです。たとえば、TLSの「書き込み」は、下位レベルで「読み込み」をトリガーします。だから、あなたはそれらの権利を得るためにこれらの懸念を分ける必要があります。
最後にMACアドレスとイーサネットフレームを直接処理する場合、TwistedにはIPとイーサネットレベルのネットワークを扱うための低レベルのライブラリTwisted Pairが含まれています。これは、Twistedの中で最も積極的に維持されている部分ではありません。コードはかなり古いです。しかし、それはうまくいくはずです。そうでなければ、真剣にバグを取り、最終的には修正されていることがわかります。私が知る限り、asyncoreには匹敵するライブラリはなく、確かにそのようなコード自体は含まれていません。
なぜ-1ですか? ... –
asyncore/asynchatは、ソケット処理に直接結びついている場合にのみ役に立つと思われます。私のコードでは、 'sniffer'はすべてのソケットの処理を行い、結果を出力します。 asyncoreがしたいのは、私の 'first'と' second'関数を実行し、 'sniffers'がデータを返すときにコールバックを発行することだけです。どうすればいい? (私はあなたにダウンバートしませんでした、btw) – dave
asyncore/asynchatは、 'select'関数呼び出し(通常はすべての非同期のものがビルドされている)の周りにオブジェクト指向のラッパーを提供します。 'select'はファイルディスクリプタで動作し、asyncore/asynchatも同様に動作します。あなたのために何かを得るために私に数分を与えてください。 –