私は、これらの新しい「工場」スタイルのネットワーク ライブラリについて自分なりの方法を学ぼうとしています。Twisted には多くの称賛が寄せられていますが、ラムダに詳しくなく、デモ コードが何を行っているかを理解する方法がよくわからないため、私にとっては絶対的な悪夢です。
デモ クライアント:
from twisted.internet import reactor, defer
from twisted.internet.protocol import ClientCreator
from twisted.protocols import amp
from ampserver import Sum, Divide
def doMath():
d1 = ClientCreator(reactor, amp.AMP).connectTCP(
'127.0.0.1', 1234).addCallback(
lambda p: p.callRemote(Sum, a=13, b=81)).addCallback(
lambda result: result['total'])
def trapZero(result):
result.trap(ZeroDivisionError)
print "Divided by zero: returning INF"
return 1e1000
d2 = ClientCreator(reactor, amp.AMP).connectTCP(
'127.0.0.1', 1234).addCallback(
lambda p: p.callRemote(Divide, numerator=1234,
denominator=0)).addErrback(trapZero)
def done(result):
print 'Done with math:', result
defer.DeferredList([d1, d2]).addCallback(done)
if __name__ == '__main__':
doMath()
reactor.run()
デモサーバー:
from twisted.protocols import amp
class Sum(amp.Command):
arguments = [('a', amp.Integer()),
('b', amp.Integer())]
response = [('total', amp.Integer())]
class Divide(amp.Command):
arguments = [('numerator', amp.Integer()),
('denominator', amp.Integer())]
response = [('result', amp.Float())]
errors = {ZeroDivisionError: 'ZERO_DIVISION'}
class Math(amp.AMP):
def sum(self, a, b):
total = a + b
print 'Did a sum: %d + %d = %d' % (a, b, total)
return {'total': total}
Sum.responder(sum)
def divide(self, numerator, denominator):
result = float(numerator) / denominator
print 'Divided: %d / %d = %f' % (numerator, denominator, result)
return {'result': result}
Divide.responder(divide)
def main():
from twisted.internet import reactor
from twisted.internet.protocol import Factory
pf = Factory()
pf.protocol = Math
reactor.listenTCP(1234, pf)
print 'started'
reactor.run()
if __name__ == '__main__':
main()
私が理解しているように、クライアントp.callRemote(Sum, a=13, b=81)
とp.callRemote(Divide, numerator=1234, denominator=0)
部分はMath.sum(13, 81)
andMath.Divide(1234, 0)
を呼び出します。これは、ファクトリ オブジェクトがクラスprotocol
に設定されているためです。Math
どういうわけか、クライアントがサーバーから戻り値を受け取ると、サブ関数Done(result)
が呼び出され、画面に内容が出力されます。
これは素晴らしいことですが、私の理解力は最悪で、すべてのドキュメントはすでにこのレベルの理解を期待しているようです。
私が本当にできるようにしたいのは、クライアントからサーバーへ、およびサーバーから接続されている複数のクライアントへデータを送信することです。このメソッドは、交換が終了するとすぐにクライアントを忘れるように見え、クライアントをreactor.run()
ブロックし、他の作業を実行できなくなります。
人々はおそらく毎日この機能を望んでいます。どうすればこれを理解できますか?
編集:クライアントが呼び出すための「チェックイン」機能を用意しようとしましたが、「報告するものはありません」と応答するだけで、サーバーがリクエストで溺れてしまうようです。また、クライアントが新しいデータを実際に利用可能になったときではなく、要求したときにのみ受信するという点で、遅延が追加されます。ファクトリ - リアクター レイアウトは、任意に応答するために保存する必要があるクライアント情報を公開していないようです。