文 | Ruslan Spivak 译 | EarlGrey

推荐 | 编程派公众号(ID:codingpy)

有一天,一位女士散步时经过一个工地,看见有三个工人在干活。她问第一个人,“你在做什么?”第一个人有点不高兴,吼道“难道你看不出来我在砌砖吗?”女士对这个答案并不满意,接着问第二个人他在做什么。第二个人回答道,“我正在建造一堵砖墙。”然后,他转向第一个人,说道:“嘿,你砌的砖已经超过墙高了。你得把最后一块砖拿下来。”女士对这个答案还是不满意,她接着问第三个人他在做什么。第三个人抬头看着天空,对她说:“我在建造这个世界上有史以来最大的教堂”。就在他望着天空出神的时候,另外两个人已经开始争吵多出的那块砖。他慢慢转向前两个人,说道:“兄弟们,别管那块砖了。这是一堵内墙,之后还会被刷上石灰的,没人会注意到这块砖。接着砌下层吧。”

这个故事的寓意在于,当你掌握了整个系统的设计,明白不同的组件是以何种方式组合在一起的(砖块,墙,教堂)时候,你就能够更快地发现并解决问题(多出的砖块)。

但是,这个故事与从头开发一个网络服务器有什么关系呢?

在我看来,要成为一名更优秀的程序员,你必须更好地理解自己日常使用的软件系统,而这就包括了编程语言、编译器、解释器、数据库与操作系统、网络服务器和网络开发框架。而要想更好、更深刻地理解这些系统,你必须从头重新开发这些系统,一步一个脚印地重来一遍。

孔子曰:不闻不若闻之,闻之不若见之,见之不若知之,知之不若行之。

不闻不若闻之

闻之不若见之

见之不若知之,知之不若行之。

译者注:上面原作者所引用的那段话在国外的翻译是:I hear and I forget, I see and I remember, I do and I understand。外国人普遍认为出自孔子,但在查找这句英文的出处时,查到有篇博文称这句话的中文实际出自荀子的《儒效篇》,经查确实如此。

我希望你读到这里的时候,已经认可了通过重新开发不同软件系统来学习其原理这种方式。

《自己动手开发网络服务器》会分为三个部分,将介绍如何从头开发一个简易网络服务器。我们这就开始吧。

首先,到底什么是网络服务器?

简而言之,它是在物理服务器上搭建的一个网络连接服务器(networking server),永久地等待客户端发送请求。当服务器收到请求之后,它会生成响应并将其返回至客户端客户端与服务器之间的通信,是以HTTP协议进行的。客户端可以是浏览器,也可以是任何支持HTTP协议的软件。

那么,网络服务器的简单实现形式会是怎样的呢?下面是我对此的理解。示例代码使用Python语言实现,不过即使你不懂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 …

接下来,在浏览器的地址栏输入这个链接:http://localhost:8888/hello,然后按下回车键,你就会看见神奇的一幕。在浏览器中,应该会出现“Hello, World!”这句话:

是不是很神奇?接下来,我们来分析背后的实现原理。

首先,我们来看你所输入的网络地址。它的名字叫URL(Uniform Resource Locator,统一资源定位符),其基本结构如下:

通过URL,你告诉了浏览器它所需要发现并连接的网络服务器地址,以及获取服务器上的页面路径。不过在浏览器发送HTTP请求之前,它首先要与目标网络服务器建立TCP连接。然后,浏览器再通过TCP连接发送HTTP请求至服务器,并等待服务器返回HTTP响应。当浏览器收到响应的时候,就会在页面上显示响应的内容,而在上面的例子中,浏览器显示的就是“Hello, World!”这句话。

那么,在客户端发送请求、服务器返回响应之前,二者究竟是如何建立起TCP连接的呢?要建立起TCP连接,服务器和客户端都使用了所谓的套接字(socket)。接下来,我们不直接使用浏览器,而是在命令行使用 telnet手动模拟浏览器。

在运行网络服务器的同一台电脑上,通过命令行开启一次 telnet会话,将需要连接的主机设置为localhost,主机的连接端口设置为8888,然后按回车键:

$ telnet localhost 8888

Trying 127.0.0.1 …

Connected to localhost.

完成这些操作之后,你其实已经与本地运行的网络服务器建立了TCP连接,随时可以发送和接收HTTP信息。在下面这张图片里,展示的是服务器接受新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)以及HTTP协议的版本。

为了尽量简化,我们目前实现的网络服务器并不会解析上面的请求,你完全可以输入一些没有任何意义的代码,也一样可以收到"Hello, World!"响应。

在你输入请求代码并按下回车键之后,客户端就将该请求发送至服务器了,服务器则会解析你发送的请求,并返回相应的HTTP响应。

下面这张图显示的是服务器返回至客户端HTTP响应详情:

我们来分析一下。响应中包含了状态行 HTTP/1.1200OK,之后是必须的空行,然后是HTTP响应的正文。

响应的状态行 HTTP/1.1200OK中,包含了HTTP版本、HTTP状态码以及与状态码相对应的原因短语(Reason Phrase)。浏览器收到响应之后,会显示响应的正文,这就是为什么你会在浏览器中看到“Hello, World!”这句话。

这就是网络服务器基本的工作原理了。简单回顾一下:网络服务器首先创建一个侦听套接字(listening socket),并开启一个永续循环接收新连接;客户端启动一个与服务器的TCP连接,成功建立连接之后,向服务器发送HTTP请求,之后服务器返回HTTP响应。要建立TCP连接,客户端和服务器都使用了套接字。

现在,你已经拥有了一个基本可用的简易网络服务器,你可以使用浏览器或其他HTTP客户端进行测试。正如上文所展示的,通过 telnet命令并手动输入HTTP请求,你自己也可以成为一个HTTP客户端

下面给大家布置一道思考题:如何在不对服务器代码作任何修改的情况下,通过该服务器运行Djando应用、Flask应用和Pyramid应用,同时满足这些不同网络框架的要求?

答案将在《自己动手开发网络服务器》系列文章的第二部分揭晓。

原文链接:http://ruslanspivak.com/lsbaws-part1/译文链接:http://codingpy.com/article/build-a-simple-web-server-part-one/

题图:pexels,CC0 授权。

sun 些命令可以将服务器设置至ok模式_Python 高手之路:从零开始打造一个Web服务器...相关推荐

  1. 服务器关闭重启后客户端socket能自动连接吗_用Python 撸一个 Web 服务器

    从一个 Hello World 程序说起 要编写 Web 服务器,需要用到一个 Python 内置库 socket.Socket 是一个比较抽象的概念,中文叫套接字,它代表一个网络连接.两台计算机之间 ...

  2. 使用Nodejs创建一个Web服务器应如何操作?以及路由相关知识了解

    文章目录 Nodejs创建一个Web服务器 Node.js创建第一个应用 Web服务器介绍 Nodejs创建一个Web服务器 路由 EJS模块引擎 Get.Post 获取GET传值 获取POST传值 ...

  3. ft服务器设置传输协议,ft服务器设置成主动模式

    ft服务器设置成主动模式 内容精选 换一换 如果您选择使用SFS Turbo实现文件共享存储,此章节操作可跳过,您可以参见<SAP HANA用户指南>中的"格式化磁盘" ...

  4. ENSP如何开启服务器的http_如何使用HTTP模块在Node.js中创建Web服务器(上)

    当你在浏览器中查看网页时,其实是在向互联网上的另一台计算机发出请求,然后它会将网页提供给你作为响应.你通过互联网与之交谈的那台计算机就是Web服务器,Web服务器从客户端(例如你的浏览器)接收HTTP ...

  5. 怎么用浏览器访问一个web服务器的某个文件

    我们在做互联网开发的时候,经常可能会遇到要访问web服务器上面某个文件的需求,那么怎么用浏览器直接访问web服务器上面的文件呢,下面本文就介绍一下. 工具/原料 Tomcat7.0.52 方法/步骤 ...

  6. api怎么写_使用Node.js原生API写一个web服务器

    Node.js是JavaScript基础上发展起来的语言,所以前端开发者应该天生就会一点.一般我们会用它来做CLI工具或者Web服务器,做Web服务器也有很多成熟的框架,比如Express和Koa.但 ...

  7. python实现一个web服务器

    一,使用python开启一个web服务器 自带的simple_server模块开启一个服务器: from wsgiref.simple_server import make_server #导入sim ...

  8. 自己写一个Web服务器(1)

    自己写一个Web服务器(1) 2016-04-13    分类:操作系统.编程开发.首页精华1人评论 分享到:更多15 本文由码农网 – 王坚原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿 ...

  9. 如何用C语言写一个web服务器的基础功能

    我们都知道,学一门语言,只是单独看了就不写的话是很容易出现眼高手低的,所以,今天摩杜云要给大家分享的内容,就是如何用C语言写一个web服务器的基础功能,希望大家看完有所收获. 服务器架构 目标架构 以 ...

最新文章

  1. MFC apps must not include windows.h
  2. 杭电信工2018期末c语言试卷,2018C程序设计期末试卷(2018杭电A卷).doc
  3. mysql insert锁机制
  4. docker高级应用之动态扩展容器空间大小
  5. 奖学金(洛谷-P1093)
  6. MPU:鸿蒙轻内核的任务栈的溢出检察官
  7. 活与死、回调以及面向对象设计
  8. 计算机硬件调查PPT,调查报告 ppt
  9. 一句话木马:ASPX篇
  10. 调剂2002年计算机科学与技术,东莞理工学院2020年硕士研究生调剂信息公告 (计算机科学与技术、资源与环境专业(原...
  11. 山东济南ISO9001认证|ISO14001认证|ISO45001认证|ISO三体系认证的流程
  12. Juce Programming Tutorial by haydxn 教程分享
  13. ele-calendar 组件的使用
  14. 关于概率dp的个人理解与总结
  15. 百度地图和51地图API应用开发
  16. Unity中利用材质自发光实现物体闪烁效果
  17. 汽车ABS控制器设计及车身稳定算法研究笔记(二)——ABS控制器硬件设计及调试
  18. android指定sim卡拨号,android – 在双SIM卡设备中使用指定的SIM拨打电话
  19. 樱花庄的宠物女孩AtCoder Grand Contest 015E - Mr.Aoki Incubator
  20. 《数字恐龙》为了一次配种,他们努力了半年

热门文章

  1. Leetcode--42.接雨水
  2. html 点击div 改变高度,HTML / CSS将div设置为同级的高度
  3. 泸西一中2021高考成绩查询,云南红河州四所好高中,红河州一中一本率领先,建水一中不容小觑...
  4. html5页面主题,HTML5页面开发笔记
  5. 路径中有中文怎么解决_时序路径分析
  6. 生产环境可以用吗_柑橘可以生产果醋吗?柑橘果醋的生产工艺是什么?
  7. 机器之心 GitHub 项目地址:
  8. Android缓存学习入门
  9. Android 逆向分析大全
  10. 使用udp协议实现服务器端程序时,用VisualC#实现UDP协议(二)