我相信,若是你想成为一个更好的开发者,你必须对平常使用的软件系统的内部结构有更深的理解,包括编程语言、编译器与解释器、数据库及操做系统、Web 服务器及 Web 框架。并且,为了更好更深刻地理解这些系统,你必须从头开始,用一砖一瓦来从新构建这个系统。html
一天,有一个正在散步的妇人刚好路过一个建筑工地,看到三个正在工做的工人。她问第一我的:“你在作什么?”第一我的没好气地喊道:“你没看到我在砌砖吗?”妇人对这个答案不满意,因而问第二我的:“你在作什么?”第二我的回答说:“我在建一堵砖墙。”说完,他转向第一我的,跟他说:“嗨,你把墙砌过头了。去把刚刚那块砖弄下来!”然而,妇人对这个答案依然不满意,因而又问了第三我的相同的问题。第三我的仰头看着天,对她说:“我在建造世界上最大的教堂。”当他回答时,第一我的和第二我的在为刚刚砌错的砖而争吵。他转向那两我的,说:“不用管那块砖了。这堵墙在室内,它会被水泥填平,没人会看见它的。去砌下一层吧。”python
这个故事告诉咱们:若是你可以理解整个系统的构造,了解系统的各个部件如何相互结合(如砖、墙还有整个教堂),你就可以更快地定位及修复问题(那块砌错的砖)。linux
若是你想从头开始创造一个 Web 服务器,那么你须要作些什么呢?web
我相信,若是你想成为一个更好的开发者,你必须对平常使用的软件系统的内部结构有更深的理解,包括编程语言、编译器与解释器、数据库及操做系统、Web 服务器及 Web 框架。并且,为了更好更深刻地理解这些系统,你必须从头开始,用一砖一瓦来从新构建这个系统。数据库
荀子曾经用这几句话来表达这种思想:编程
我但愿你如今可以意识到,从新建造一个软件系统来了解它的工做方式是一个好主意。浏览器
在这个由三篇文章组成的系列中,我将会教你构建你本身的 Web 服务器。咱们开始吧~服务器
先说首要问题:Web 服务器是什么?网络
简而言之,它是一个运行在一个物理服务器上的网络服务器(啊呀,服务器套服务器),等待客户端向其发送请求。当它接收请求后,会生成一个响应,并回送至客户端。客户端和服务端之间经过 HTTP 协议来实现相互交流。客户端能够是你的浏览器,也能够是使用 HTTP 协议的其它任何软件。框架
最简单的 Web 服务器实现应该是什么样的呢?这里我给出个人实现。这个例子由 Python 写成,即便你没据说过 Python(它是一门超级容易上手的语言,快去试试看!),你也应该可以从代码及注释中理解其中的理念:
import socket HOST, PORT = '', 8888 listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) listen_socket.bind((HOST, PORT)) listen_socket.listen(1) print 'Serving HTTP on port %s ...' % PORT while True: client_connection, client_address = listen_socket.accept() request = client_connection.recv(1024) print request http_response = """/ HTTP/1.1 200 OK Hello, World! """ client_connection.sendall(http_response) client_connection.close()
将以上代码保存为 webserver1.py,或者直接从 GitHub 上下载这个文件。而后,在命令行中运行这个程序。像这样:
$ python webserver1.py Serving HTTP on port 8888 …
如今,在你的网页浏览器的地址栏中输入 URL:http://localhost:8888/hello ,敲一下回车,而后来见证奇迹。你应该看到“Hello, World!”显示在你的浏览器中,就像下图那样:
说真的,快去试一试。你作实验的时候,我会等着你的。
完成了?不错!如今咱们来讨论一下它其实是怎么工做的。
首先咱们从你刚刚输入的 Web 地址开始。它叫 URL,这是它的基本结构:
URL 是一个 Web 服务器的地址,浏览器用这个地址来寻找并链接 Web 服务器,并将上面的内容返回给你。在你的浏览器可以发送 HTTP 请求以前,它须要与 Web 服务器创建一个 TCP 链接。而后会在 TCP 链接中发送 HTTP 请求,并等待服务器返回 HTTP 响应。当你的浏览器收到响应后,就会显示其内容,在上面的例子中,它显示了“Hello, World!”。
咱们来进一步探索在发送 HTTP 请求以前,客户端与服务器创建 TCP 链接的过程。为了创建连接,它们使用了所谓“套接字(socket)”。咱们如今不直接使用浏览器发送请求,而在命令行中使用 telnet 来人工模拟这个过程。
在你运行 Web 服务器的电脑上,在命令行中创建一个 telnet 会话,指定一个本地域名,使用端口 8888,而后按下回车:
$ telnet localhost 8888 Trying 127.0.0.1 … Connected to localhost.
这个时候,你已经与运行在你本地主机的服务器创建了一个 TCP 链接。在下图中,你能够看到一个服务器从头开始,到可以创建 TCP 链接的基本过程。
在同一个 telnet 会话中,输入 GET /hello HTTP/1.1,而后输入回车:
$ telnet localhost 8888 Trying 127.0.0.1 … Connected to localhost. GET /hello HTTP/1.1 HTTP/1.1 200 OK Hello, World!
你刚刚手动模拟了你的浏览器(的工做)!你发送了 HTTP 请求,而且收到了一个 HTTP 应答。下面是一个 HTTP 请求的基本结构:
HTTP 请求的第一行由三部分组成:HTTP 方法(GET,由于咱们想让咱们的服务器返回一些内容),以及标明所需页面的路径 hello,还有协议版本。
为了简单一些,咱们刚刚构建的 Web 服务器彻底忽略了上面的请求内容。你也能够试着输入一些无用内容而不是“GET /hello HTTP/1.1”,但你仍然会收到一个“Hello, World!”响应。
一旦你输入了请求行并敲了回车,客户端就会将请求发送至服务器;服务器读取请求行,就会返回相应的 HTTP 响应。
下面是服务器返回客户端(在上面的例子里是 telnet)的响应内容:
咱们来解析它。这个响应由三部分组成:一个状态行 HTTP/1.1 200 OK,后面跟着一个空行,再下面是响应正文。
HTTP 响应的状态行 HTTP/1.1 200 OK 包含了 HTTP 版本号,HTTP 状态码以及 HTTP 状态短语“OK”。当浏览器收到响应后,它会将响应正文显示出来,这也就是为何你会在浏览器中看到“Hello, World!”。
以上就是 Web 服务器的基本工做模型。总结一下:Web 服务器建立一个处于监听状态的套接字,循环接收新的链接。客户端创建 TCP 链接成功后,会向服务器发送 HTTP 请求,而后服务器会以一个 HTTP 响应作应答,客户端会将 HTTP 的响应内容显示给用户。为了创建 TCP 链接,客户端和服务端均会使用套接字。
如今,你应该了解了 Web 服务器的基本工做方式,你可使用浏览器或其它 HTTP 客户端进行试验。若是你尝试过、观察过,你应该也可以使用 telnet,人工编写 HTTP 请求,成为一个“人形” HTTP 客户端。
如今留一个小问题:“你要如何在不对程序作任何改动的状况下,在你刚刚搭建起来的 Web 服务器上适配 Django, Flask 或 Pyramid 应用呢?”
我会在本系列的第二部分中来详细讲解。敬请期待。
顺便,我在撰写一本名为《搭个 Web 服务器:从头开始》的书。这本书讲解了如何从头开始编写一个基本的 Web 服务器,里面包含本文中没有的更多细节。订阅邮件列表,你就能够获取到这本书的最新进展,以及发布日期。
本文转载地址:https://www.linuxprobe.com/get-web-servers.html