python 服务器_用 Python 实现简易 Web 服务器

本文介绍了如何使用Python实现一个简单的Web服务器,包括HTTP协议的基础、动态生成页面、提供静态文件、处理目录列表和CGI协议等内容。通过一个示例程序展示了如何创建一个基本的Web服务器,以及如何扩展其功能,如处理目录请求和运行外部CGI程序。
摘要由CSDN通过智能技术生成

? 点击上方蓝字“Python猫”,免费获得一个公众号

花下猫语:上篇文章推荐了一本神书《500 Lines or Less》(点此阅读),有几位读者留言问是否有中文版。很遗憾,还没有。不过我在文中也说了,Github 上有个翻译计划,已收录了 10 几篇译文。这些文章的代码量虽然不多,但是因为讲解的内容很详细,所以篇幅都很长。今天就先给大家分享其中一篇吧。如果你感兴趣的话,上篇文章末尾附了链接,可去查看。

61db7cf9449cdf86601d362d8216c84b.png

图 | 宫崎骏电影《侧耳倾听》

作者简介:Greg Wilson 是 Software Carpentry(一个科学家和工程师的计算技巧速成班)的创始人。他在工业界和学术界工作了三十余年,是好几本计算相关图书的作者或编辑,包括了 2008 年 Jolt 图书奖得主 Beautiful Code开源软件架构 的前两卷。1993 年,Greg 获得了爱丁堡大学的计算机博士学位。

简介

在过去的二十多年里,网络改变了社会的各个方面,但它的核心却改动不多。大多数系统仍然遵循着 Tim Berners-Lee 在 25 年前所制定的规则。尤其是,大多数 Web 服务器仍旧以相同的方式处理着相同的数据,一如既往。

本章节将探讨它们如何实现。与此同时,本章节还将探讨开发者如何创建增加新特性而不需要重写的软件系统。

背景

几乎所有的网络程序都运行在一类叫做 互联网协议(IP)的通信标准上。这类协议中,我们涉及的是传输控制协议(TCP/IP),该协议使得计算机间通信类似于读写文件。

程序通过套接字使用 IP 协议进行通信。每个套接字是点对点通信信道的一端,正如电话机是一次电话通信的一端。一个套接字包含着一个 IP 地址,该地址确定了一台确定的机器和该机器上的一个端口号。IP 地址包含了四个八位数字,比如 174.136.14.108;域名系统将这些数字与字符相匹配,比如 aosabook.org,以便于记忆。

端口号码是 0 - 65535 之间的一个随机数,唯一确定了主机上的套接字。(如果说 IP 地址像一家公司的电话号码,那么端口号就像是分机号。)端口 0 - 1023 预留给操作系统使用;任何人都可以使用剩下的端口。

超文本传输协议(HTTP)描述了程序通过 IP 协议交换数据的一种方法。HTTP 协议刻意设计得简单: 客户端通过套接字发送一个请求,指定请求的东西,服务器在响应中返回一些数据(如下图)。该数据或许复制自硬盘上的文件,或许由程序动态生成,或是二者的混合。

6fe4bdb2fd8db06caf0c69d0a5a25e1a.png

关于 HTTP 请求,最重要的地方在于,它仅由文本组成。任何有意愿的程序都可以对其进行创建或解析。不过,为了被正确地解析,文本中必须包含下图所展示的部分。

6f190aee9dce9470a11799b2253c5199.png

(注: 'sp':空格, 'cr lf':换行) HTTP 方法大多是 GET(请求信息)或者 POST(提交表单或上传文件)。统一资源定位器(URL)确定了客户端所请求的文件路径,一般位于硬盘上,比如 /research/experiments.html, 但是(接下来才是关键),如何处理完全取决于服务器。HTTP 版本一般是 "HTTP/1.0" 或 "HTTP/1.1" ; 二者之间的差异对我们来说并不重要。

HTTP 首部(Headers)是一组键值对,如同下面这三行:

Accept: text/html
Accept-Language: en, fr
If-Modified-Since: 16-May-2005

不同于哈希表中的键,HTTP 首部中,键可以出现任意多次。这将允许请求做一些事,例如指定愿意接收多种类型的内容。

最后,请求的主体是与请求关联的任何数据。这个应用于通过表单提交数据,上传文件等。首部的末尾和主体的开头之间必须由一个空行,以声明首部的结束。

首部中,Content-Lenght告诉服务器在请求主体中有多少字节需要被读取。

HTTP 响应的格式与 HTTP 请求类似:

685294a5b65f8d90ea0bd28122901e1e.png

版本号,首部,主体有着相同的格式和意义。状态码是一个数字,用来指示在处理请求时所发生的事情: 200 意味着 "一切工作正常",404 意味着 "没有找到",其他状态码也分别有着各自的含义。状态词以易读的形式重复着上述信息,比如 "一切正常" 或是 "没有找到"。

本节中,我们只需要了解关于 HTTP 的两件事情。

第一,HTTP 是无状态的: 每个请求自行处理,服务器在两个请求之间不会记住任何东西。如果应用想要跟踪一些信息,比如用户的身份,它必须自己实现。

实现的方法通常使用 cookie, 这是服务器发送到客户端的短字符串,之后由客户端返回给服务器。当用户执行一些函数,需要在多个请求之间保存状态时,服务器会创建一个新的 cookie,将它存储在数据库中,然后发送给浏览器。每次浏览器返回 cookie,服务器通过 cookie 寻找关于用户行为的信息。

我们需要了解的第二点是,可以填充参数以提供更多的信息。比如说,如果我们使用搜索引擎,我们需要指定关键词。我们可以将这些附加到 URL 路径中,但更应该是在 URL 中附加参数。我们在 URL 后附加 '?' ,之后是以 '&' 分隔的键值对('key=value')。比如说,URL http://www.google.ca?q=Python 要求谷歌查询关于 Python 的页面: 键是字母 'q',值是 'Python'。长一点的查询 http://www.google.ca/search?q=Python&client=Firefox,告诉谷歌我们在使用 Firefox,诸如此类。我们可以传输任何参数,不过,哪些参数需要注意,如何解释这些参数,完全取决于网站上运行的程序。

当然,如果 '?' 和 '&' 用作特殊字符,必然有方法加以避免,正如必须有方法将一个双引号字符放置在由双引号分隔的字符串内。URL 编码标准使用 '%' 后跟两位代码表示特殊字符,并使用 '+' 字符替代空格。因此,我们使用 URLhttp://www.google.ca/search?q=grade+%3D+A%2B在谷歌中搜索 "grade = A+"(注意空格)。

打开套接字,构建 HTTP 请求,解析响应极其乏味,因此大多数用户使用库来做大部分工作。Python 附带了一个这样的库,叫做 urllib2(因为它是之前的库 urllib 的代替者),但是它暴露了许多大多数用户不关心的东西。相比于 urllib2Requests 库是一个更加易于使用的选择。接下来是一个例子,使用 Requests 下载来自 AOSA book 站点的一个页面。

import requests
response = requests.get('http://aosabook.org/en/500L/web-server/testpage.html')
print 'status code:', response.status_code
print 'content length:', response.headers['content-length']
print response.text
status code: 20
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值