• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

HTTP一实现一个最简单的基于http协议的web服务器基于python

文章目录[隐藏]

这篇文章的最后起源是《计算机网络:自顶向下》的第7版的第2章(应用层)开端,套接字编程作业第一题试验题。通过这个试验作业,学习 Python 中 TCP 连贯的套接字编程基础知识:如何创立一个套接字,将其绑定到特定的地址和端口,以及发送和接管 HTTP 数据包。同时也学习一些 HTTP 报文格式的基础知识。

指标:开发一个一次解决一个 HTTP 申请的 Web 服务器。 这个 Web 服务器应该承受并解析 HTTP 申请,从服务器的文件系统中获取申请的文件,创立一个 HTTP 响应音讯,该音讯由申请的文件和题目行组成,而后将响应间接发送到客户端。 如果服务器中不存在申请的文件,则服务器应将 HTTP “404 Not Found”音讯发送回客户端。

一、回顾http协定

HTTP(超文本传输协定)是在TCP/IP协定族中的一种应用层协定,除了HTTP以外,预存在TCP/IP协定族中的应用层协定还包含出名的FTP(用于文件传输服务),SMTP(简略邮件传输协定,其余的邮件协定还有POP3),DNS(域名解析零碎)等等。

准备常识:URI 对立资源定位符

须要意识URI这个货色,uniform resource identification(和URL差不多,然而比URL更加具体,因为它定义了每一个网络资源单位的相对地址门路)。HTTP 协定应用 URI 定位互联网上的资源。


这就是一个URI的格局示意图(图自《图解HTTP》)【留神:URI不辨别大小写】,上面是几个不同协定的URI的示例:

ftp://ftp.is.co.za/rfc/rfc1808.txt
http://www.ietf.org/rfc/rfc23…
ldap://[2001:db8::7]/c=GB?objectClass?one
mailto:[email protected]
news:comp.infosystems.www.servers.unix
tel:+1-816-555-1212
telnet://192.0.2.16:80/
urn:oasis:names:specification:docbook:dtd:xml:4.1.2

接下来讲述 HTTP的报文构造

HTTP用于客户端与服务端的通信,通过申请和响应的替换达成通信。具体过程为:由客户端发动申请,服务器接管到,而后回复响应报文。

申请报文

书上的两个http申请报文的例子:

第1局部(第1行),申请行(request line):包含字段:办法、URI和协定版本

  • 办法取值:根底的有5个,POST GET HEAD PUT DELETE 【留神辨别大小写!须要用大写字母

    【辨析GET与POST】简略讲讲GET和POST的区别:GET和POST 都可能获取网络资源,GET是间接申请获取页面,POST是提交表单让服务器返回后果资源。概念上,大略辨别上面几点即可(不做web开发的话)。
    (1)GET把参数蕴含在URL中,POST通过request body传递参数。相对而言,GET比POST更不平安,因为参数间接裸露在URL上,然而因为都是http没加密,所以实质上都不平安。
    (2)GET在浏览器回退时是有害的,而POST会再次提交申请。
    (3)GET申请参数会被残缺保留在浏览器历史记录里,而POST中的参数不会被保留。
    (4)GET产生一个TCP数据包;POST产生两个TCP数据包。对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。对于GET形式的申请,浏览器会把http header和data一并发送进来,服务器响应200(返回数据)。(并不是所有浏览器都会在POST中发送两次包,Firefox就只发送一次)
    (5)它们其实有时候能够混用,实质上都是通过TCP封装
    【PUT和DELETE办法】HTTP/1.1 的 PUT和DELETE 办法本身不带验证机制, 任何人都能够上传或删除文件 , 存在安全性问题, 因而个别的 Web 网站不应用该办法。
  • URI:上文曾经给出了定义
    1) 如果不是拜访特定资源而是对服务器自身发动申请, 能够用一个 * 来代替申请 URI
    2) 能够应用残缺的域名+服务器门路作为URI,也能够把域名填在首部行的 Host 字段

* 协定版本
例子中都是HTTP/1.1
【阐明:历史上的HTTP版本:(1)HTTP/0.9: HTTP 于 1990 年问世。 那时的 HTTP 并没有作为正式的规范被建设。含有 HTTP1.0 之前版本的意思, 因而被称为 HTTP/0.9。(2)HTTP/1.0:HTTP 正式作为规范被颁布是在 1996年5月,版本被命名为 HTTP/1.0,并记录于 RFC1945 1。虽说是初期规范,但该协定规范至今仍被宽泛应用在服务器端。(3)HTTP/1.1:1997年1月颁布的 HTTP/1.1 是目前支流的 HTTP 协定版本。当初的规范是 RFC2068,之后公布的修订版 RFC2616 就是以后的最新版本 2 (4)HTTP/2.0 协定的次要目标是进步网页性能,目前尚未宽泛应用】

第2局部(第2~K行),首部行(header line) 蕴含字段:各种首部字段(分为三类申请首部,通用首部和实体首部),每个首部字段别离占一行,格局为: 首部字段名+空格+值+CRLF(换行符)。上面是首部格局的示意图:

第3局部 空行 间接一个CRLF

第4局部 实体体(entity body)
GET办法时,实体体为空。POST办法时候才应用(将这些内容提交下来)。HEAD办法也为空,因为这个个别用于调试追踪(响应不返回申请的内容,只返回首部)。

总结
以上4局部合起来,形成一个申请报文,格局如下:

响应报文

仍旧是从一个例子开始,

能够看到,响应报文由状态行,首部行,空行和实体体形成

  • 状态行:包含 协定版本 状态码 状态码起因短语
    协定版本:例如 HTTP/1.0
    状态码:仅记录在 RFC2616 上的 HTTP 状态码就达 40 种,加上其余的就更多。

    然而只有记住14种就能够:
    200 OK
    204 no content 没有理论内容,申请已胜利解决, 但在返回的响应报文中不含实体的主体局部
    206 Partial Content 客户端收回的是获取资源的局部范畴申请,Content-Range指定
    301 Moved Permanently 申请的资源已被调配了新的 URI
    302 Found 该状态码示意申请的资源已被调配了新的 URI, 心愿用户(本次) 能应用新的 URI 拜访
    303 See Other 因为申请对应的资源存在着另一个 URI, 应应用 GET办法定向获取申请的资源
    304 Not Modified 客户端发送的是附带条件的申请,服务器端容许申请拜访资源, 但没有满足条件的状况。附带条件的申请是指采纳 GET办法的申请报文中蕴含 If-Match, If-ModifiedSince, If-None-Match, If-Range, If-Unmodified-Since 中任一首部。
    307 Temporary Redirect 长期重定向 和302差不多
    400 Bad Request 申请报文有语法错误
    401 Unauthorized 发送的申请须要有通过 HTTP 认证(BASIC 认证、DIGEST 认证) 的认证信息
    403 Forbidden 服务器回绝拜访资源,服务器能够不阐明起因,如要阐明起因则填写在响应报文的实体体,个别可能是例如文件权限,从未受权的发送源IP地址试图拜访等起因
    404 Not Found 找不到或者服务器不想通知你他有这个资源
    500 Internal Server Error 服务器外部故障
    503 Service Unavailable 服务器超负荷或者停机保护,当初无奈解决申请。
  • 首部行:这里次要钻研的是合乎HTTP/1.1的标准的首部字段

    响应报文的首部行和申请报文的差不多,只是字段 不再有申请报文字段而是改为响应报文字段
  • 空行和实体体
  • 总结

申请报文和响应报文的首部行

下面提到了,这两种报文的首部行有很多字段,能够分为四类 通用首部字段,实体首部字段,申请首部字段(申请报文),响应首部字段(响应报文)
接下来给出具体定义:

通用首部字段

申请首部字段

响应首部字段

实体首部字段

更具体的解释以及它们的用法须要再去查看RFC文档或者相干书籍

二、实现一个搭建web服务器的简略实例(python)

http是基于tcp连贯的,因而首先要把握一下 python中 tcp通信的根本接口用法。

服务端socket通信

  1. 导包
    from socket import *
  2. 创立一个socket:
    serverSocket = socket(AF_INET, SOCK_STREAM)
  3. 绑定本地端口
    serverSocket.bind("127.0.0.1", 80)
  4. 设置监听,操作系统能够挂起的最大连贯数量设置为5
    serverSocket.listen(5)
  5. 监听期待一个内部进来的连贯,返回一个新的socket示意这个连贯,以及提取出客户端的地址
    connectionSocket, addr = serverSocket.accept()
  6. 一旦连贯胜利,则从客户端处获取数据
    message = connectionSocket.recv(1024)

筹备一个简略的html文件
例如我筹备的 hello.html 如下

<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>

<body>
    你好啊, 蠢才
</body>
</html>

放到程序同目录下

而后写web server的主程序
web_server.py:

from socket import *
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(("127.0.0.1", 80))
serverSocket.listen(5)

while True:
    print("ready to serve")
    connectionSocket, addr = serverSocket.accept()
    try:
        # establish connection
        message = connectionSocket.recv(20000)
        # print(message)
        filename = message.split()[1]
        f = open(filename[1:], 'rb')
        outputdata = f.readlines()
        # send on HTTP Header line into socket
        header = bytearray('HTTP/1.1 200 OK\r\n Date: Sat, 28 May 2022 18:10:01 GMT \r\n Content-Type: text/html \r\n \r\n ', 'utf-8')
        connectionSocket.send(header)

        # send to content of the requested file to the client
        for i in range(0, len(outputdata)):
            connectionSocket.send(outputdata[i])
        connectionSocket.close()

    except IOError:
        header = bytearray('HTTP/1.1 404 Not Found\r\n Date: Tue, 03 Jul 2012 04:40:59 GMT \r\n Content-Type: text/html \r\n \r\n ', 'utf-8')
        connectionSocket.send(header)       
        connectionSocket.close()

serverSocket.close()

程序里明确了让它运行在 本地 127.0.0.1的 80 端口上,因而运行程序当前,在浏览器关上如下网址即可获取到这个html的内容

http://127.0.0.1:80/hello.html

如果出错了,获取不到那个文件,会返回404

后记:遗留下的一些问题

1)古代的web服务,除了本文最根底的HTTP协定外,还有很多重要的实现和个性,包含:长久连贯,pipeline作业, cookie, SSL加密,压缩编码传输,分块传输 这些是什么?
2)web服务如何精确响应返回多个文件内容?例如加了CSS和各种图片文件元素的网页
3)如何解决高并发的拜访申请?

上述问题会在后续的系列里持续具体说。


喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址