2010年10月8日星期五

Django 服务器的一点认识

概念较多,很多地方暂没法求甚解,只能做一些感性的介绍,说的不清楚或有错误的地方大家再讨论。

以下代码可能有省略。

1. HTTP 基本原理

  • 服务器上需要运行 web server 软件(下面以 nginx 为例,常见的还有 apache、lighttpd),nginx 以守护进程模式运行后,默认监听 tcp 的 80 端口,准备响应客户端的请求。
  • 客户端(这里指浏览器)需要访问站点时,浏览器打开本地一个临时端口,主动向服务器上的 80 端口建立 tcp 连接,以和 nginx 进程进行通信。
  • 连接建立后,浏览器发起请求


    GET /index.html HTTP/1.1
    HOST: test.com

  • nginx 响应请求,这里客户端请求的是静态文件,直接返回即可;对于动态内容的请求,见下一小节

HTTP/1.1 200 OK
Content-type: text/html
Date: Mon, 26 Apr 2010 20:23:51 GMT
Server: nginx/0.6.35

1e24
<html>
<head>
<title>首页</title>
<script type="text/javascript" src="http://test.com/jiaoben.js"></script>
</head>
..........................
..........................
</html>
0

Connection closed by foreign host.

此响应包含 http header 和 html文本 两大部分。

  • 浏览器解析响应。对于 html 响应中包含的元素,需要进行新的一次请求,如上例中的 js 文件;若浏览器和服务器软件协商打开 keepalive 模式,则此次新的请求可以在已有的 tcp 连接上进行,否则需要重新三次握手来建立新连接。


2. 动态内容处理

往往我们看到的网页都是用各种语言动态生成的,如 PHP 语言和使用 python 语言的 django 框架。

  • 用户输入 http://www.test.com/ 这样的 url,请求网站的根目录。
  • 对于 php,配置服务器,指定默认的响应文件,如 index.php,并且配置以何种方式处理以 .php 结尾的文件。

    location / {
    index index.php;
    location ~ \.php$ {
    fastcgi_pass 127.0.0.1:9000; # 我们以这种方式来处理 php 文件,某程序监听了本机的9000端口。
    }
    }

    location 后面跟的是相对目录,即 url 中 host 后面的目录部分。

  • 对于 django 这种提供较完善解决方案的框架,它靠匹配 url 来进行决策,我们就不指定默认文件了,把所有请求全部交给某程序处理,配置如下。

    location / {
    fastcgi_pass 127.0.0.1:8000;
    }

    我们还可以控制让静态文件直接由 nginx 返回而不让 django 处理。

    location /static/ {
    alias /var/www/djangoproject/static/;
    }

上述配置使用了 fastcgi 的方式,由 web server 将请求转交给监听在 8000 端口的 fastcgi 服务器,fastcgi 服务器处理后返回结果给 web server,再由 web server 返回给浏览器,流程如下图(图片源自《python 核心编程》)。



2.1 CGI & FASTCGI

apache、lighttpd 等 web server 软件都支持传统的 CGI,在简单配置后,将如下脚本(hello.py)放入指定目录。

#!/usr/bin/python
print "Content-type: text/html"
print ""
print ""
print "Hello World"
print ""

然后访问 http://test.com/cgi-path/hello.py 就能看到相应内容了。

其处理的过程大概是这样:对于每一个请求,创建一个新进程,然后初始化并执行上述程序,最后将数据返回给 web server 并释放内存资源。

后来出现的 fastcgi 方式对传统方法进行了改进,首先启动一个或多个 fastcgi 进程(可理解为 fastcgi 服务器/网关),然后对于每一个浏览器请求,web server 去连接已经启动好的 fastcgi 进程并转发请求,待得到结果后关闭此连接。

当然 fastcgi 方式和协议需要服务器软件支持,上述 3 种 web server 软件都支持,有关 fastcgi 好处和性能的讨论这里不再介绍,网上一抓一大把。

2.2 django

对于 django,概念有些拗口,注意区分 fastcgi 方式和协议的区别。

  • WSGI,Web Server Gateway Interface,是 Python 应用程序和 Web 服务器之间的一种接口,以 fastcgi 作为两者通信的底层协议规范

  • django 能以 fastcgi 方式(而不是协议)启动自带的服务器进程,此进程叫做 WSGIServer,该 server 由 python 的 flup 库提供,具体采用什么协议可以在 manage.py runfcgi 的 protocol 参数中指定,注意除了fastcgi 协议(参数中写为 fcgi)还能选择 scgi 等其他协议。

  • 现在我们知道 WSGIServer 就是上面介绍的 fastcgi 服务器/网关,它监听一个 tcp 端口(还能以 unix socket 方式监听,这里不再介绍),也就是前面配置文件中的 8000 端口。

  • 在启动 WSGIServer 的时候需要指定一个 WSGIHandler,这个 Handler 关联了请求(request)和我们写的 django 应用,在每次请求到来时 Handler 会加载应用的 settings、middleware 和 环境变量,然后请求经 url 解析并交给指定 views 处理,最终处理结果返回给 WSGIServer。


一些参考:
  • django/core/servers/fastcgi.py
  • django/core/handlers/wsgi.py
  • http://blogs.sun.com/oswald/entry/good_idea_python_with_fastcgi CGI 和 FASTCGI 的区别
  • http://osdcpapers.cgpublisher.com/product/pub.84/prod.21 WSGI 入门的 PDF
  • http://www.douban.com/note/13508388/ WSGI、flup、fastcgi、web.py的关系

2010年8月19日星期四

Linux Boot Process

from Red Hat Linux Reference Guide http://www.redhat.com/docs/manuals/linux/

Below are the basic stages of the boot process for an x86 system:
  1. The system BIOS checks the system and launches the first stage boot loader on the MBR of the primary hard disk.
  2. The first stage boot loader loads itself into memory and launches the second stage boot loader from the /boot/ partition.
  3. The second stage boot loader loads the kernel into memory, which in turn loads any necessary modules and mounts the root partition read-only.
  4. The kernel transfers control of the boot process to the /sbin/init program.
  5. The /sbin/init program loads all services and user-space tools, and mounts all partitions listed in /etc/fstab.
  6. The user is presented with a login prompt for the freshly booted Linux system.

2009年12月9日星期三

Something about Migrating(Deploying) Website on Linux

根据需要,将网站从一台服务器迁移到另一台服务器上(两台服务器基本相同,汗,因为都是同一个学长配置的)。

oj 为项目代号,代码只是简写,并不完整。
  1. 创建分支

    决定将主线发布,将其放进发布分支中
    svn cp svn://trunk svn://branches/RB-0.99
    直接操作代码仓库,而不是本地工作目录

  2. 在目标服务器工作目录迁出
    svn co svn://branches/RB-0.99 oj
    tips: svn客户端无法保存密码时请检查~/.subversion目录权限以及其中配置文件

  3. 将原服务器中未版本控制的文件(如用户图片)导入新的服务器中
    sudo scp -r dir
    这里使用了管理员权限复制,确保能复制非当前用户身份的文件,如 www-data 身份的数据文件权限身份的保留参考 getfacl

  4. 修改相关配置文件及其权限,数据库迁移部分省略。

    文件与同服务器其他非管理员用户的关系应该是怎样的?这一点没想通。

  5. lighttpd 部分
    $http["url"] =~ "^oj($|/)" {
    dir-listing.activate = "disable"
    }

    url.access-deny += ( ".xxx" )
    一个是防止站点以文件方式浏览,另一个是防止重要文件被下载。


2009年3月15日星期日

尝试用Linux学习工作

假期读到一片文章《完全用Linux 工作》,那是铁杆用户。我们没接触过Linux 的同学可以尝尝鲜,try it ,你会学到很多有趣并且实用的东西。

说到Linux ,你首先想到的是不友好的命令行?我来简单介绍一下,Linux 其实只是系统内部看不见的核心部分,很多软件包括带图形界面的都可运行在Linux 内核之上。习惯了Windows 的用户用不着担心,Linux 提供了一些同Windows 长得差不多的桌面环境,桌面环境也是那许许多多的软件之一,最流行的是GnomeKDE 两大桌面。

开放是Linux 的一个理念,提供给用户多种选项,然后由用户来做决定。最初的决定是安装什么Linux 发行版,许多公司组织有自己发行的版本,大多是免费的。老大哥Fedora ,欧洲最流行的openSUSE ,近几年很火的Ubuntu ,这三大社区发行版是我们入门很好的选择,因为它们背后有很不错的社区支持,遇到问题可以很方便的查询解决,不会像百度知道那样叫你重装系统:p 。在这里个人推荐使用教育网的同学安装Ubuntu ,两个原因,一是教育网软件源丰富(软件源是你下载软件的地方),二是国内使用的人多,论坛很火,很多使用经验会被分享出来,熟悉了Ubuntu 再换其他的也不迟。Ubuntu 的默认桌面是Gnome ,很简单,会用Windows 就行,管理、设置等常见的也不用教了,毕竟都有中文版的。

上网的问题不得不谈,这是关键,否则电脑就基本废了,普通局域网插上网线就OKADSL 同样不难,在配置DSL 的地方填上用户名密码即可;宿舍教育网上网就要麻烦一点,需要安装上网客户端(华为什么的),新用户对命令行下安装软件不太了解的话,叫身边会的同学帮助你吧。

接下来是安装软件,其实系统装好时已经自带了常用软件,需要自己安装的是一些第三方软件比如显卡驱动程序。软件源或者叫软件仓库是困扰新人的一个地方,特别是使用教育网的用户,我们需要删除原有的并添加教育网的仓库地址,每个发行版的配置方法不同,这个得好好Google 下网上的教程。各个Linux 版本都有自己的软件管理器,在里面只需点下鼠标就能下载安装想要的软件了,步骤是搜索- 选中- 安装。

最后按惯例推荐些Linux 流行的软件,办公除了OpenOffice.org 之外还可以试试同MS Office 兼容得更好的永中Office 个人版;看视频推荐SmplayerVLC Player 也是一个很好的选择;即时通讯方面QQ 已经有官方的版本,飞信则有民间的LibFetionFirefoxOpera 浏览器不用再介绍,令人期待的Google 浏览器今年也要发布;然后是开发学习方面,C/C++ IDE 中有实用CodeBlockC#.NET 也有了Linux 的环境——Monoftp 客户端是教育网用户少不了的软件,FileZilla 完全能胜任,中文ftp 站点别忘了修改成GBK 字符集。

另外,别错过了周末的InstallFest 安装节 ,不多打广告,详情见http://www.beihang-osc.org/

(原发表于校内网)

2008年12月8日星期一

双系统、杂分区的一点经验

  • 首先假设你已经用PQ这种权威分区工具分完并格式化多个主分区+扩展分区、逻辑分区(请有经验的装系统爱好者来做这件事,而且需要安装系统的分区尽量不要格式化)。
  1. 装系统顺序不多说,是先Windows再Linux,否则需要进行多余的步骤。最重要的是,正常安装XP(原版CD而非Ghost版等修改版)时如果检测到你的硬盘含非ntfs、fat32主分区(也可能只是检测第一个主分区)的话你将无法进入安装界面,会提示你硬盘有错(具体是什么忘了),而且没有很好的解决方法,国外网估计能找到答案。所以请先删除Linux分区再安装XP,你用Ghost安装我没话说。
  2. 用Linux特别是Ubuntu发行版中自带的分区软件时请注意:
    当你安装Ubuntu到了分区这一步时,采用他的建议一般不是你想要的方案,有些时候还会将你的分区一分为二,强烈建议手动。手动时也不要太豪放乱改大小(Resize),特别是主分区和扩展分区两者之间的resize,的确你想怎么改就怎么改,但如果你的分区本来就有点复杂,这时的修改看上去没什么事,实际上会将你的分区结构改得很乱,不利于以后的维护。(还是Suse好,分区建议什么的都比较合理)
  3. 如果你犯了第二点中所说的错误,而且你用的是XP,请不要随意用XP中自带磁盘管理(Disk Management),牵一发而动全身,我删除了第二个主分区(linux分区)时中了招,磁盘管理直接将我的扩展分区全部删除。。这是第二次了遇到了,第一次是把扩展分区删了一半。
  • 加点关键字方便robot搜到:恢复误删分区,恢复分区,撤销删除分区,格式化后恢复文件
  • 如果你中了上面第3点所说的招,或者自己不小心删除了分区时这时不要乱动!不要再操作分区了,自己重新建立分区再用恢复文件的软件恢复资料是极其恶心的,双系统的话最好别重启(Grub所在分区没了就没法引导)。这时推荐使用DiskGenius,以前叫Diskman,这个共享软件也帮了我的大忙;Linux下可以使用TestDisk(英文版),ubuntu的默认软件源里有,suse在官网也能搜到。
  • DiskGenius能搜索并恢复分区表,即使你没备份,保存后一切同原来一样了,注意用dos工具箱中的diskfix是无法搜索到自己手动删除的分区的。
  • 如果当时真的乱动了,你也可能搜索到你想要的分区,可以用DiskGenius浏览原来的文件并恢复到其他分区上,这样你可以不用恢复分区而只恢复文件。
  • 如果删除了Grub所在分区,重启时你将无法找到操作系统,所以重启前你可以用DiskGenius重建硬盘的mbr。
  • 如果重启无法找到操作系统了,你可以用XP安装盘中的恢复控制台恢复引导,或者用含紧急引导的工具盘引导XP后执行上面那一步。
  • 估计这个帖子对大家作用甚微,希望大家的资料没有出大问题吧,数据无价啊。
  • 最后鄙视一下某些电脑生产厂商将硬盘的四个主分区用得干干净净。

2008年12月6日星期六

完全二叉树的一些判定方法

  1. 肉眼
  2. 顺序表储存
    完全二叉树的每个结点按层次遍历顺序从1编号至n,所以当1 ~ n有某一项为空时则不为完全二叉树,时间复杂度O(n)。
  3. 链表储存
    受顺序表储存的启发,在树结点结构中添加一数据域,记录当前结点编号。编号在建树时不难确定,根节点编号为1,插入结点时,若父亲结点编号为i,则左儿子编号为2*i,右儿子为2*i+1。随后进行一次层次遍历,若已遍历结点数+1不等于当前队首结点编号,则不为完全二叉树,时间复杂度O(n)。此法由于添加了编号,使结点删除操作受到限制,所以在不涉及删除操作的情况下此法比较容易实现。
    一般情况下的判定方法也不难,网上流传的是
    先要对二叉树进行层次遍历,在遍历过程中对每一个结点进行检查:
    (1)如果当前结点没有右子树,则剩下的全部结点必须既没有左子树,又没有右子树;
    (2)如果当前结点有右子树,则它必须也有左子树.
    如果同时满足(1)(2),则是完全二叉树;否则不是.
    时间复杂度同样为O(n),但没有对树的维护造成麻烦。

  4. 相信还有更好的方法,这学期的核心即是学习强大的二叉树。

2008年11月22日星期六

Construction/Destruction Order of QObjects


int main()
{
     QPushButton quit("Quit");
     QWidget window;
     quit.setParent(&window);
     ...
 }

In this case, the order of destruction causes a problem. The parent's destructor is called first because it was created last. It then calls the destructor of its child, quit, which is incorrect because quit is a local variable. When quit subsequently goes out of scope, its destructor is called again, this time correctly, but the damage has already been done.

Remember: When the destructor of the child(quit) is called first, it removes itself from its parent(window), before the destructor of parent is called. Anyway the child will not be called twice. You MUST "delete" the object manually which is created with "New" and don't have a parent!