twisted 诗歌客户端代码分析:嵌套着的多层deferred。
来源:互联网 发布:星际2 不平衡 知乎 编辑:程序博客网 时间:2024/05/18 17:03
http://krondo.com/?p=2159
http://blog.sina.com.cn/s/blog_704b6af70100qay3.html
花了很长的时间才看懂了这段代码的运行过程。该代码是上面两个网页中的twisted 教程中的第13部分的内容,旨在使用嵌套式的deferred建立一个诗歌下载客户端。
这篇文章的主要难点在于对多层deferred的callback函数的调用顺序的理解。
1.服务器提供诗歌的下载和诗歌的转换,两个功能。
2.该客户端首先从服务器上面下载诗歌,之后再使用服务器,对诗歌进行转换。
3.建立两个protocol,两个Factory.
4.PoetryProtocol与PoetryClientFactory用于下载诗歌。
5.TransformClientProtocol与TransformClientFactory用于对诗歌进行转换。
6.在主函数main中进行了三次添加callback。分别为:
d.addCallback(try_to_cummingsify)
d.addCallbacks(got_poem,poem_failed)
d.addBoth(poem_done)
7.在get_poetry(host,port)中为外部的deferred生成处。该函数建立TCP链接,从服务器端下载诗歌。
如果下载成功则在poem_finished中调用callback。则try_to_cummingsify开始执行。
否则,在clientConnectionFailed中调用errback。则首先pass_through然后直接执行poem_failed,再执行peom_done结束。
8.在try_to_cummingsify中建立了一个内部deferred,并且建立TCP链接,传输当前poem到服务器,然后接受转换好了的poem。并且向内部的deferred添加了一个callback
d.addErrback(fail)
9.如果cummingsify成功,则调用handlePoem,在handlePoem调用callback。由于内部deferred中之添加了fail作为errback。因此这个callback是直接pass_through的。10.如果cummingsify失败,则调用clientConnectionLost,在其中调用d.errback,此时实际上执行了fail函数。
11.这时候外层的try_to_cummingsify函数执行完毕。开始执行got_poem。如果cummingsify成功,这时的poem为cum后的poem。否则为原poem,因为fail函数返回原poem。
12.最后执行poem_done,结束。
源代码如下:
# This is the Twisted Get Poetry Now! client, version 6.0import optparse, sysfrom twisted.internet import deferfrom twisted.internet.protocol import Protocol, ClientFactoryfrom twisted.protocols.basic import NetstringReceiverdef parse_args(): usage = """usage: %prog [options] [hostname]:port ...This is the Get Poetry Now! client, Twisted version 6.0Run it like this:python get-poetry.py xform-port port1 port2 ...If you are in the base directory of the twisted-intro package,you could run it like this:python twisted-client-6/get-poetry.py 10001 10002 10003to grab poetry from servers on ports 10002, and 10003 and transformit using the server on port 10001.Of course, there need to be appropriate servers listening on thoseports for that to work.""" parser = optparse.OptionParser(usage) _, addresses = parser.parse_args() if len(addresses) < 2: print parser.format_help() parser.exit() def parse_address(addr): if ':' not in addr: host = '127.0.0.1' port = addr else: host, port = addr.split(':', 1) if not port.isdigit(): parser.error('Ports must be integers.') return host, int(port) return map(parse_address, addresses)class PoetryProtocol(Protocol): poem = '' def dataReceived(self, data): self.poem += data def connectionLost(self, reason): self.poemReceived(self.poem) def poemReceived(self, poem): self.factory.poem_finished(poem)class PoetryClientFactory(ClientFactory): protocol = PoetryProtocol def __init__(self, deferred): self.deferred = deferred def poem_finished(self, poem): if self.deferred is not None: d, self.deferred = self.deferred, None d.callback(poem) def clientConnectionFailed(self, connector, reason): if self.deferred is not None: d, self.deferred = self.deferred, None d.errback(reason)class TransformClientProtocol(NetstringReceiver): def connectionMade(self): self.sendRequest(self.factory.xform_name, self.factory.poem) def sendRequest(self, xform_name, poem): self.sendString(xform_name + '.' + poem) def stringReceived(self, s): self.transport.loseConnection() self.poemReceived(s) def poemReceived(self, poem): self.factory.handlePoem(poem)class TransformClientFactory(ClientFactory): protocol = TransformClientProtocol def __init__(self, xform_name, poem): self.xform_name = xform_name self.poem = poem self.deferred = defer.Deferred() def handlePoem(self, poem): d, self.deferred = self.deferred, None d.callback(poem) def clientConnectionLost(self, _, reason): if self.deferred is not None: d, self.deferred = self.deferred, None d.errback(reason) clientConnectionFailed = clientConnectionLostclass TransformProxy(object): """I proxy requests to a transformation service.""" def __init__(self, host, port): self.host = host self.port = port def xform(self, xform_name, poem): factory = TransformClientFactory(xform_name, poem) from twisted.internet import reactor reactor.connectTCP(self.host, self.port, factory) return factory.deferreddef get_poetry(host, port): """Download a poem from the given host and port. This functionreturns a Deferred which will be fired with the complete text ofthe poem or a Failure if the poem could not be downloaded.""" d = defer.Deferred() from twisted.internet import reactor factory = PoetryClientFactory(d) reactor.connectTCP(host, port, factory) return ddef poetry_main(): addresses = parse_args() xform_addr = addresses.pop(0) proxy = TransformProxy(*xform_addr) from twisted.internet import reactor poems = [] errors = [] def try_to_cummingsify(poem): d = proxy.xform('cummingsify', poem) def fail(err): print >>sys.stderr, 'Cummingsify failed!' return poem return d.addErrback(fail) def got_poem(poem): print poem poems.append(poem) def poem_failed(err): print >>sys.stderr, 'The poem download failed.' errors.append(err) def poem_done(_): if len(poems) + len(errors) == len(addresses): reactor.stop() for address in addresses: host, port = address d = get_poetry(host, port) d.addCallback(try_to_cummingsify) d.addCallbacks(got_poem, poem_failed) d.addBoth(poem_done) reactor.run()if __name__ == '__main__': poetry_main()
- twisted 诗歌客户端代码分析:嵌套着的多层deferred。
- twisted入门教程之八:使用Deferred的诗歌下载客户端
- 使用Deferred的诗歌下载客户端
- twisted入门教程之四:由Twisted支持的诗歌客户端
- Twisted源码分析4--Deferred
- twisted入门教程之五:由Twited支持的诗歌下载服务客户端
- twisted deferred
- twisted中deferred异步的理解
- 跟踪 twisted 里deferred 的Callback
- 对twisted 中deferred异步的理解
- 理解Twisted的Deferred机制(一)
- twisted入门教程之十三:使用Deferred新功能实现新客户端
- Deferred Object In Twisted
- twisted Deferred學習筆記一
- twisted异步机制-Deferred
- twisted Deferred學習筆記一
- twisted异步机制--Deferred
- 集合框架_集合多层嵌套的代码体现
- 每日一句英语
- 经验交流:浅谈研发团队的组建
- 想要写好的程序应该远离计算机
- 关于pragma pack的用法
- 我的游戏之路(8)
- twisted 诗歌客户端代码分析:嵌套着的多层deferred。
- struts2核心工作流程与原理
- 茶
- 《csharp高级编程》 学习笔记 第三章 对象和类型
- C语言学习笔记(14指针)
- C++编译器优化:Copy Elision(省略不必要的拷贝)
- jquery中的jsonp使用(cross-domain的一个方法)
- xshell的注册码
- Android 找到本地联络人并向其发邮件