为四川人民祈祷! www.onefoundation.cn
logo of kjam.org
Archive: 2007-4

New Banner

如果你不是Pythoner,请忽略本消息
...
大家快往上看,什么?你在看RSS!混蛋,快点打开浏览器
大家现在可以欣赏我华丽抄袭来的新Banner了,我喜欢这个idea!

...


似曾相识?快点打开你python命令行
comments: 74  
by kernel1983

详解asyncore.py

asyncore库是python的一个标准库,它是一个异步socket的包装。我们操作网络的时候可以直接使用socket等底层的库,但是asyncore使得我们可以更加方便的操作网络,避免直接使用socket,select,poll等工具时需要面对的复杂。

这个库很简单,包含了一个函数和一个类
* loop()函数
* dispatcher基类
需要注意的是,loop函数是全局的,不是dispatcher的方法

每一个从dispatcher继承的类的对象,都可以看作我们需要处理的一个socket,可以是TCP连接或者UDP,甚至是其它不常用的。使用容易,我们需要定义一个类,它继承dispatcher,然后我们重写(覆盖)一些方法就可以了。

我们需要重写的方法一般都以handle_打头。
class refuse(dispatcher):
    def handle_accept():
        #do nothing ...
        pass

loop()函数负责检测一个dict,dict中保存dispatcher的实例,这个字典被称为channel。每次创建一个dispatcher对象,都会把自己加入到一个默认的dict里面去(当然也可以自己指定channel)。当对象被加入到channel中的时候,socket的行为都已经被定义好,程序只需要调用loop(),一切功能就实现了。

asyncore是python标准库中的一个良好的设计
在python的标准文档中,有一个asyncore的例子
import asyncore, socket

class http_client(asyncore.dispatcher): def __init__(self, host, path): asyncore.dispatcher.__init__(self) self.create_socket(socket.AF_INET, socket.SOCK_STREAM) self.connect( (host, 80) ) self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path
def handle_connect(self): pass
def handle_close(self): self.close()
def handle_read(self): print self.recv(8192)
def writable(self): return (len(self.buffer) > 0)
def handle_write(self): sent = self.send(self.buffer) self.buffer = self.buffer[sent:]
c = http_client('www.python.org', '/')
asyncore.loop()

运行这个函数,发现python.org的首页被下载下来了,也就是说我们实现了一个http层的协议?但是我们用的仅仅是socket级别的API...那么来看看这几行代码的奥妙吧!

writable和readable在检测到一个socket可以写入或者检测到数据到达的时候,被调用,并返回一个bool来决定是否handle_read或者handle_write

打开asyncore.py可以看到,dispatcher类中定义的方法writable和readable的定义相当的简单:
    def readable(self):
        return True

def writable(self): return True

就是说,一旦检测到可读或可写,就直接调用handle_read/handle_write,但是在上面的例子中,我们却看到了一个重载(看上去像C++的虚函数,不是吗?)
    def writable(self):
        return (len(self.buffer) > 0)

很明显,当我们有数据需要发送的时候,我们才给writable的调用者返回一个True,这样就不需要在handle_write中再做判断了,逻辑很明确,代码很清晰,美中不足的是理解需要一点时间,但是不算困难吧!

其余的代码看起来就很清晰了,有一种并来将挡的感觉。当一个http服务器发送处理完成你的请求,close socket的时候,我们的handle_close()也相应完成自己的使命。close()将对象自身从channel中删除,并且负责销毁socket对象。
    def close(self):
        self.del_channel()
        self.socket.close()

loop()函数检测到一个空的channel,将退出循环,程序完成任务,exit。
comments: 135  
by kernel1983

Jampad - V2 in Python

最近正在做的一项工作,就是重新写一遍Jampad。

在刚刚过去的那个时代,Jampad这个简单够用的wiki是一个基于PHP的程序。本来以为程序很小,甚至不需要封装。事实证明在PHP这样的Perl式语法(带美元符号的语法)中,结构化编程带来的副作用是巨大的,你永远都不会期待这样一个无比巨大的case

现在的计划是用Python重新让我的Jampad跑起来,并保留原来的数据。重新制造轮子已经是我们笑话刚刚入门的Geek们的时候经常使用的话题,所以现在的代码绝对不能从零开始,于是我追随着时间轴找到了一个使用Python写作的,古老的CGI程序——pikipiki,并加以改造

如果你看过我前几天写的文章,或许你会明白我的意图了——WSGI,没错,把一个CGI程序Port到一个基于WSGI的标准,这样我们有机会摆脱掉任何框架~~~Django,TurboGears,Pylons……邪恶的思想萌芽,让人热血沸腾

这样的好处就是,享受Python世界中对于WSGI的一切优点,你的程序可以被CGI或者FCGI等任意的环境支持。我好像一直在重复这个观点

OK!
I‘ve got a target.
comments: 0 | tags: Jampad   
by kernel1983

小玩一把Lighttpd

前些日子有了支持Python的空间以后,怀着跑步进入共产主义的心情,把iBook上的Apache2,PHP5全部给枪毙了。一时间满心欢喜⋯⋯

但是,麻烦一下子来了。昨天一个朋友托我搞定一个PHP问题,我顿时傻眼了。幸运的是,找遍了整个硬盘,虽然没有发现apachectl的影子,却在/usr/sbin下面找到了httpd,虽然法医坚定,属于apache1.3的尸体,在我看来却是救命稻草!不要高兴的太早,因为系统依然无法运行,继续检查,修复了几个配置文件中的错误,Apache 1.3 + PHP 4.44,复活了。三下五除二解决了问题

想来想去,lighttpd还没有玩过,那就趁热打铁,挥舞lighttpd+fcgi成就一下现代版本的PHP5环境把!总体的感觉,lighttpd比apache简单多了。enable mod_fastcgi,指明php的路径,总的来说就是去掉几个#注释,就大公告成了,速度也是相当的没话说。过几天,自己的wsgi程序也要在这上面跑跑才带劲。

还有,SCGI也支持,那都要玩一下
comments: 1030  
by kernel1983

WSGI与Apache,无关

理论上说来,两者应该完全没有关系。WSGI应用程序需要一个WSGIServer,当然这只是一个标准,实际上的实现可能会有很多。当然,如果你连WSGI是什么都完全搞不清楚,建议你先看看PEP333

WSGIClient很容易实现,简单到只需要一个函数就可以搞定,比“hello,java”更加容易的明白
def simple_app(environ, start_response):

status = '200 OK'
response_headers = [('Content-type','text/plain')]
start_response(status, response_headers)
return ['Hello world!\n']

我们这里拿出来玩的WSGIServer是框架CheryPy中的一部分,它可以被剥离出来单独使用,源代码的开头注释部分告诉你怎么实现一个标准的"Hello,WSGI"。这样一个服务器在开发时候做测试是完全没有问题的,但是要放到互联网上被成千上万的流量考验,估计没有人敢这么做。

所以我们得找个坚固的东西,Apache是选择之一,是惯性的选择,虽然不够创新,但是还是很多人这么选择了。但是我们之前就说过了,WSGI和Apache几乎什么关系都没有,一个是Python语言的接口,另外一个是C语言的服务器。

CGI是最通用的做法,任何语言都可以这样做。面对请求,Apache可以把请求转换成一个进程的启动,把参数作为环境变量,把标准输出重定向为网页上的内容。

写一个WSGI2CGI的程序看来可行,但是CGI的效率不高,已经是远近闻名的事情了。

所以为了要支持新的功能,Apache需要写module。

Module是Apache扩展自己的主要手段,module就是一个动态连接库,使用C写成。但是,我们不需要自己写,因为已经有现成的给我们用了,而且还不只一个。他们是mod_python和mod_fcgi,还有mod_scgi

最有名的就是FastCGI,根据传言效率也比mod_python好一些,我自己的网站也跑在FastCGI上。FastCGI的标准也支持众多的语言,WSGI2FCGI的库也有一些现成的可以使用了。

...
其实这不是How to式的文章,我需要阐明的是:

写web程序的时候,坚持WSGI的标准(其实WSGIClient本身很容易),或者采用使用WSGI标准的框架,就可以在部署的时候充分利用现有的很多便利的工具。如果是Java,因为Servlet是私有的标准,所以只能被部署在Java应用服务器上。

WSGI与Apache本身是没有关系的,但是很多人对Apache感情深厚,在学习WSGI的时候总是心系Apache,很好奇这样一个协议是如何与我们现在的web服务器结合起来的。这样反倒不容易理解WSGI标准本身。或许我们应该考虑的是WSGI是怎么与FastCGI/SCGI联系起来的

除了WSGI Client和Server以外,WSGI还有对Middleware的定义,以后再详细讨论
comments: 2900  
by kernel1983
123