Chinaunix首页 | 论坛 | 博客
  • 博客访问: 5119537
  • 博文数量: 921
  • 博客积分: 16037
  • 博客等级: 上将
  • 技术积分: 8469
  • 用 户 组: 普通用户
  • 注册时间: 2006-04-05 02:08
文章分类

全部博文(921)

文章存档

2020年(1)

2019年(3)

2018年(3)

2017年(6)

2016年(47)

2015年(72)

2014年(25)

2013年(72)

2012年(125)

2011年(182)

2010年(42)

2009年(14)

2008年(85)

2007年(89)

2006年(155)

分类: Python/Ruby

2013-05-28 13:12:35

Twisted是一个功能极为强大的异步网络应用开发库——当然是Python的。印象中大概也就只有ACE有这么强悍,但Twisted在易用性方面要好很多——这其中当然少不了Python的功劳(ACE是用C++的)。

但Python也有其缺点,其中之一就是因为GIL的存在使得用Python写多线程应用的意义不大,那么对于像Twisted这样基于Reactor模式实现的单一Event Loop的应用开发环境来说,就有一点局限:整个应用(或者说整个进程)都必须围绕着reactor来。这样的话做一些纯后端的应用是没什么问题,比如像网页爬虫(Scrapy就是基于Twsited的)一类的应用。但这显然不够,很多应用还是需要有前端界面的——比如像BT、电驴这样的下载工具。MLDonkey采用的方法就是提供一个WEB的管理界面来与用户交互——当然,MLDonkey并不是用Python开发的。

这是一个很好的思路。所以Twisted提供了一套WEB开发环境以实现这样的目的。

关于twisted.web部分的开发,官方的文档 显得太过于简单了,特别是连基本的request对象的参考文档都没有。还好gashero整理了一部分在《 》,引用一下(有补充):

channel :包含上级的HTTP协议对象。
transport :通信对象。
method :HTTP方法,如GET和POST。
uri :全部请求的URI。
path :具体的请求路径,不含参数。
args :请求参数,包括URL参数和POST参数。格式如 {’key’:[’val1′,’val2′],} 。
received_headers :请求报文的头字段。
received_cookies :请求报文的cookie。
content :请求报文的实体主体,文件对象。
clientproto :发出请求的客户端的HTTP版本。
client :请求的客户端地址对象,包括type、host和port属性,分别记录协议(这里固定为TCP)、IP和端口号
host :本机接收请求的地址对象
getHeader(key) :获取请求的头字段。
getCookie(key) :获取请求的cookie。
getAllHeaders() :所有请求的头字段字典,就是返回received_headers。
getRequestHostname() :请求的host字段,不含端口号。
getHost() :原始请求的通信地址,返回host。
getClientIP() :获取客户端IP。
getUser() :获取basic验证中的用户名。
getPassword() :获取basic验证中的密码。
getClient() :获取客户端地址对象

一个最基本的Web应用如下:

  1. from twisted.web import server, resource
  2. from twisted.internet import reactor
  3. class Simple(resource.Resource):
  4.     isLeaf=True
  5.     def render_GET(self, request):
  6.         return "Hello, world!"
  7. reactor.listenTCP(8080, server.Site(Simple()))
  8. reactor.run()

然后运行起来就可以通过URL: 访问这个程序的页面了。

注意其中的的isLeaf是必须的。不过也还有另一种方法可以实现同样的功能

  1. from twisted.web import server, resource
  2. from twisted.internet import reactor
  3. class Simple(resource.Resource):
  4.     def __init__(self):
  5.         resource.Resource.__init__(self)
  6.         self.putChild("", self)
  7.     def render_GET(self, request):
  8.         return "Hello, world!"
  9. reactor.listenTCP(8080, server.Site(Simple()))
  10. reactor.run()
这个方法好理解,就是把这个对象挂到请求链接的根目录上。以此类推就可以实现带子目录请求的页面:


  1. from twisted.web import server, resource
  2. from twisted.internet import reactor
  3. class ChildSimple(resource.Resource):
  4.     isLeaf=True
  5.     def render_GET(self, request):
  6.         return "Hello, child!"
  7. class Simple(resource.Resource):
  8.     def __init__(self):
  9.         resource.Resource.__init__(self)
  10.         self.putChild("", self)
  11.         self.putChild("child", ChildSimple())
  12.     def render_GET(self, request):
  13.         return "Hello, world!"
  14. reactor.listenTCP(8080, server.Site(Simple()))
  15. reactor.run()

现在可以通过URL:/child 访问这个子页面了。不过生成子页面还有一个动态的办法:


  1. from twisted.web import server, resource
  2. from twisted.internet import reactor
  3. class ChildSimple(resource.Resource):
  4.     isLeaf=True
  5.     def __init__(self, id):
  6.         resource.Resource.__init__(self)
  7.         self.id=id
  8.     def render_GET(self, request):
  9.         return "Hello, No. %s visitor!" % self.id
  10. class Simple(resource.Resource):
  11.     def __init__(self):
  12.         resource.Resource.__init__(self)
  13.         self.putChild("", self)
  14.     def render_GET(self, request):
  15.         return "Hello, world!"
  16.     def getChild(self, path, request):
  17.         return ChildSimple(path)
  18. reactor.listenTCP(8080, server.Site(Simple()))
  19. reactor.run()

现在可以试试URL:/1234 访问了。其中1234可以换成任何数字(实际上上面的程序对此未作限制,即使输入任何字符也是可以的)。

接下来是静态内容的使用:


  1. from twisted.web import server, resource, static
  2. from twisted.internet import reactor
  3. class Simple(resource.Resource):
  4.     def __init__(self):
  5.         resource.Resource.__init__(self)
  6.         self.putChild("", self)
  7.         self.putChild("static", static.File("/var/www/htdocs"))
  8.     def render_GET(self, request):
  9.         return "Hello, world!"
  10. reactor.listenTCP(8080, server.Site(Simple()))
  11. reactor.run()

访问一下URL:/static 试试就知道了。

这些对于Web开发都是些基本的功能,稍微复杂一点的网页要做起来还是很痛苦的。但是Python是很灵活的东西,资源也很丰富,所以实际上问题也不大。比如在getChild方法里加上routing的实现,再加一个mako一类的模板,功能立即强大很多(貌似搞得像Pylons了)——只是数据库操作还是需要谨慎一些,简单地加上SQLAlchemy之类的ORM也不是不行,但是它对数据库的访问是阻塞式的,可能导致Twisted应用的性能下降很大。

所幸的是一般来说为Twisted应用增加Web交互界面很少还有需要操作数据库的,即使必须要有,Twisted也提供了异步的数据库访问接口——虽然功能不可能像SQLAlchemy那么强大,对于简单的应用应该也足够了。

虽然WEB界面已经很方便了,但也许还会有人想要用交互式GUI,这也没问题。Twisted的Web库提供了对XMLRPC和SOAP的支持。以简单一些的XMLRPC为例:


  1. from twisted.web import server, resource, xmlrpc
  2. from twisted.internet import reactor
  3. class XREcho(xmlrpc.XMLRPC):
  4.     def xmlrpc_echo(self, bar):
  5.         return bar
  6. reactor.listenTCP(8080, server.Site(XREcho()))
  7. reactor.run()

客户端的调用方式是:


  1. import xmlrpclib
  2. s = xmlrpclib.Server("/")
  3. s.echo("Hello!")

上面的代码执行后将回显。

实际上XMLRPC对象也是一种Resource,所以也可以简单地用putChild放到子目录下去。或者如果需要对xmlrpc的request进行控制——比如增加authentication或者其它的客户端调用限制,可以在_cbRender方法里实现,具体可参考web.xmlrpc的源码。

关于用Twisted进行Web开发的更多内容请参考官方文档和源码。



文章来自:http://blog.csdn.net/raptor/article/details/5602878













阅读(1819) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~