胆囊息肉

注册

 

发新话题 回复该主题

网络编程懒人入门六深入浅出,全面理解 [复制链接]

1#

本文引用了自简书作者“涤生_Woo”的文章,内容有删减,感谢原作者的分享。

1、前言

HTTP(全称超文本传输协议,英文全称HyperTextTransferProtocol)是互联网上应用最为广泛的一种网络协议。所有的WWW文件都必须遵守这个标准。设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法。对于移动端即时通讯(尤其IM应用)来说,现今主流的数据通信总结下来无外乎就是长连接+短连接的方式,而短连接在应用上讲就是本文将要介绍的HTTP协议的应用,而而正确地理解HTTP协议对于写好IM来说,是相当有益的(关于移动端的HTTP具体应用情况,可以阅读《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》)。本篇文章篇幅比较长,先来个思维导图预览一下:

(本文同步发布于:52im.net/thread--1-1.html)

2、“HTTP之父”其人

▲“HTTP之父”——TedNelson▲HTTP协议logo年TedNelson构思了一种通过计算机处理文本信息的方法,并称之为超文本(hypertext),这成为了HTTP超文本传输协议标准架构的发展根基。TedNelson组织协调万维网协会(WorldWideWebConsortium)和Internet工作小组(InternetEngineeringTaskForce)共同合作研究,最终发布了一系列的RFC,其中最著名的就是RFC。RFC定义了HTTP协议的我们今天普遍使用的一个版本——HTTP1.1。由于TedNelson对HTTP技术的发展做出的突破性历史贡献,他被称为“HTTP之父”。

3、系列文章

本文是系列文章中的第6篇,本系列文章的大纲如下:

《网络编程懒人入门(一):快速理解网络通信协议(上篇)》《网络编程懒人入门(二):快速理解网络通信协议(下篇)》《网络编程懒人入门(三):快速理解TCP协议一篇就够》《网络编程懒人入门(四):快速理解TCP和UDP的差异》《网络编程懒人入门(五):快速理解为什么说UDP有时比TCP更有优势》《网络编程懒人入门(六):深入浅出,全面理解HTTP协议》(本文)

如果您觉得本系列文章过于基础,您可直接阅读《不为人知的网络编程》系列文章,该系列目录如下:

《不为人知的网络编程(一):浅析TCP协议中的疑难杂症(上篇)》《不为人知的网络编程(二):浅析TCP协议中的疑难杂症(下篇)》《不为人知的网络编程(三):关闭TCP连接时为什么会TIME_WAIT、CLOSE_WAIT》《不为人知的网络编程(四):深入研究分析TCP的异常关闭》《不为人知的网络编程(五):UDP的连接性和负载均衡》《不为人知的网络编程(六):深入地理解UDP协议并用好它》

关于移动端网络特性及优化手段的总结性文章请见:

《现代移动端网络短连接的优化手段总结:请求速度、弱网适应、安全保障》《移动端IM开发者必读(一):通俗易懂,理解移动网络的“弱”和“慢”》《移动端IM开发者必读(二):史上最全移动弱网络优化方法总结》

4、参考资料

《TCP/IP详解-第11章·UDP:用户数据报协议》《TCP/IP详解-第17章·TCP:传输控制协议》《TCP/IP详解-第18章·TCP连接的建立与终止》《TCP/IP详解-第21章·TCP的超时与重传》《通俗易懂-深入理解TCP协议(上):理论基础》《通俗易懂-深入理解TCP协议(下):RTT、滑动窗口、拥塞处理》《理论经典:TCP协议的3次握手与4次挥手过程详解》《理论联系实际:Wireshark抓包分析TCP3次握手、4次挥手过程》《计算机网络通讯协议关系图(中文珍藏版)》《高性能网络编程(一):单台服务器并发TCP连接数到底可以有多少》《高性能网络编程(二):上一个10年,著名的C10K并发连接问题》《高性能网络编程(三):下一个10年,是时候考虑C10M并发问题了》《高性能网络编程(四):从C10K到C10M高性能网络应用的理论探索》《简述传输层协议TCP和UDP的区别》《为什么QQ用的是UDP协议而不是TCP协议?》《移动端即时通讯协议选择:UDP还是TCP?》

5、HTTP概述

5.1计算机网络体系结构分层

5.2TCP/IP通信传输流

利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则从链路层往上走。TCP/IP通信传输流如下:

首先作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的HTTP请求;接着,为了传输方便,在传输层(TCP协议)把从应用层处收到的数据(HTTP请求报文)进行分割,并在各个报文上打上标记序号及端口号后转发给网络层;在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。这样一来,发往网络的通信请求就准备齐全了;接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的HTTP请求。

HTTP请求如下图所示:在网络体系结构中,包含了众多的网络协议,这篇文章主要围绕HTTP协议(HTTP/1.1版本)展开。

HTTP协议(HyperTextTransferProtocol,超文本传输协议)是用于从WWW服务器传输超文本到本地浏览器的传输协议。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。HTTP是客户端浏览器或其他程序与Web服务器之间的应用层通信协议。在Internet上的Web服务器上存放的都是超文本信息,客户机需要通过HTTP协议传输所要访问的超文本信息。HTTP包含命令和传输信息,不仅可用于Web访问,也可以用于其他因特网/内联网应用系统之间的通信,从而实现各类应用资源超媒体访问的集成。我们在浏览器的地址栏里输入的网站地址叫做URL(UniformResourceLocator,统一资源定位符)。就像每家每户都有一个门牌地址一样,每个网页也都有一个Internet地址。当你在浏览器的地址框中输入一个URL或是单击一个超级链接时,URL就确定了要浏览的地址。浏览器通过超文本传输协议(HTTP),将Web服务器上站点的网页代码提取出来,并翻译成漂亮的网页。

6、HTTP工作过程

HTTP请求响应模型:HTTP通信机制是在一次完整的HTTP通信过程中,客户端与服务器之间将完成下列7个步骤:

1)建立TCP连接:在HTTP工作开始之前,客户端首先要通过网络与服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后,才能进行高层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80;2)客户端向服务器发送请求命令:一旦建立了TCP连接,客户端就会向服务器发送请求命令;例如:GET/sample/hello.jspHTTP/1.1;3)客户端发送请求头信息:客户端发送其请求命令之后,还要以头信息的形式向服务器发送一些别的信息,之后客户端发送了一空白行来通知服务器,它已经结束了该头信息的发送;4)服务器应答:客户端向服务器发出请求后,服务器会客户端返回响应;例如:HTTP/1.OK响应的第一部分是协议的版本号和响应状态码;5)服务器返回响应头信息:正如客户端会随同请求发送关于自身的信息一样,服务器也会随同响应向用户发送关于它自己的数据及被请求的文档;6)服务器向客户端发送数据:服务器向客户端发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束,接着,它就以Content-Type响应头信息所描述的格式发送用户所请求的实际数据;7)服务器关闭TCP连接:一般情况下,一旦服务器向客户端返回了请求数据,它就要关闭TCP连接,然后如果客户端或者服务器在其头信息加入了这行代码Connection:keep-alive,TCP连接在发送后将仍然保持打开状态,于是,客户端可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。

7、HTTP协议基础

7.1通过请求和响应的交换达成通信

应用HTTP协议时,必定是一端担任客户端角色,另一端担任服务器端角色。仅从一条通信线路来说,服务器端和客服端的角色是确定的。HTTP协议规定,请求从客户端发出,最后服务器端响应该请求并返回。换句话说,肯定是先从客户端开始建立通信的,服务器端在没有接收到请求之前不会发送响应。

7.2HTTP是不保存状态的协议

HTTP是一种无状态协议。协议自身不对请求和响应之间的通信状态进行保存。也就是说在HTTP这个级别,协议对于发送过的请求或响应都不做持久化处理。这是为了更快地处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计成如此简单的。可是随着Web的不断发展,我们的很多业务都需要对通信状态进行保存。于是我们引入了Cookie技术。有了Cookie再用HTTP协议通信,就可以管理状态了。

7.3使用Cookie的状态管理

Cookie技术通过在请求和响应报文中写入Cookie信息来控制客户端的状态。Cookie会根据从服务器端发送的响应报文内的一个叫做Set-Cookie的首部字段信息,通知客户端保存Cookie。当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值后发送出去。服务器端发现客户端发送过来的Cookie后,会去检查究竟是从哪一个客户端发来的连接请求,然后对比服务器上的记录,最后得到之前的状态信息。Cookie的流程:

7.4请求URI定位资源

HTTP协议使用URI定位互联网上的资源。正是因为URI的特定功能,在互联网上任意位置的资源都能访问到。

7.5告知服务器意图的HTTP方法(HTTP/1.1)

7.6持久连接

HTTP协议的初始版本中,每进行一个HTTP通信都要断开一次TCP连接。比如使用浏览器浏览一个包含多张图片的HTML页面时,在发送请求访问HTML页面资源的同时,也会请求该HTML页面里包含的其他资源。因此,每次的请求都会造成无畏的TCP连接建立和断开,增加通信量的开销。为了解决上述TCP连接的问题,HTTP/1.1和部分HTTP/1.0想出了持久连接的方法。其特点是,只要任意一端没有明确提出断开连接,则保持TCP连接状态。旨在建立一次TCP连接后进行多次请求和响应的交互。在HTTP/1.1中,所有的连接默认都是持久连接。

7.7管线化

持久连接使得多数请求以管线化方式发送成为可能。以前发送请求后需等待并接收到响应,才能发送下一个请求。管线化技术出现后,不用等待亦可发送下一个请求。这样就能做到同时并行发送多个请求,而不需要一个接一个地等待响应了。比如,当请求一个包含多张图片的HTML页面时,与挨个连接相比,用持久连接可以让请求更快结束。而管线化技术要比持久连接速度更快。请求数越多,时间差就越明显。

8、HTTP协议报文结构

8.1HTTP报文

用于HTTP协议交互的信息被称为HTTP报文。请求端(客户端)的HTTP报文叫做请求报文;响应端(服务器端)的叫做响应报文。HTTP报文本身是由多行(用CR+LF作换行符)数据构成的字符串文本。

8.2HTTP报文结构

HTTP报文大致可分为报文首部和报文主体两部分。两者由最初出现的空行(CR+LF)来划分。通常,并不一定有报文主体。HTTP报文结构如下:

8.3请求报文结构

请求报文的首部内容由以下数据组成:

请求行——包含用于请求的方法、请求URI和HTTP版本;首部字段——包含表示请求的各种条件和属性的各类首部。(通用首部、请求首部、实体首部以及RFC里未定义的首部如Cookie等)。

请求报文的示例,如下:

8.4响应报文结构

响应报文的首部内容由以下数据组成:

状态行——包含表明响应结果的状态码、原因短语和HTTP版本;首部字段——包含表示请求的各种条件和属性的各类首部。(通用首部、响应首部、实体首部以及RFC里未定义的首部如Cookie等)。

响应报文的示例,如下:

服务器不支持请求中指明的HTTP协议版本。

12、HTTP报文实体

12.1HTTP报文实体概述

大家请仔细看看上面示例中,各个组成部分对应的内容。接着,我们来看看报文和实体的概念。如果把HTTP报文想象成因特网货运系统中的箱子,那么HTTP实体就是报文中实际的货物。

报文:是网络中交换和传输的数据单元,即站点一次性要发送的数据块。报文包含了将要发送的完整的数据信息,其长短很不一致,长度不限且可变;实体:作为请求或响应的有效载荷数据(补充项)被传输,其内容由实体首部和实体主体组成。(实体首部相关内容在上面第六点中已有阐述。)

我们可以看到,上面示例右图中深红色框的内容就是报文的实体部分,而蓝色框的两部分内容分别就是实体首部和实体主体。而左图中粉红框内容就是报文主体。通常,报文主体等于实体主体。只有当传输中进行编码操作时,实体主体的内容发生变化,才导致它和报文主体产生差异。

12.2内容编码

HTTP应用程序有时在发送之前需要对内容进行编码。例如,在把很大的HTML文档发送给通过慢速连接上来的客户端之前,服务器可能会对其进行压缩,这样有助于减少传输实体的时间。服务器还可以把内容搅乱或加密,以此来防止未授权的第三方看到文档的内容。这种类型的编码是在发送方应用到内容之上的。当内容经过内容编码后,编好码的数据就放在实体主体中,像往常一样发送给接收方。内容编码类型:

12.3传输编码

内容编码是对报文的主体进行的可逆变换,是和内容的具体格式细节紧密相关的。传输编码也是作用在实体主体上的可逆变换,但使用它们是由于架构方面的原因,同内容的格式无关。使用传输编码是为了改变报文中的数据在网络上传输的方式。

12.4分块编码

分块编码把报文分割成若干已知大小的块。块之间是紧挨着发送的,这样就不需要在发送之前知道整个报文的大小了。分块编码是一种传输编码,是报文的属性。若客户端与服务器端之间不是持久连接,客户端就不需要知道它在读取的主体的长度,而只需要读取到服务器关闭主体连接为止。当使用持久连接时,在服务器写主体之前,必须知道它的大小并在Content-Length首部中发送。如果服务器动态创建内容,就可能在发送之前无法知道主体的长度。分块编码为这种困难提供了解决方案,只要允许服务器把主体分块发送,说明每块的大小就可以了。因为主体是动态创建的,服务器可以缓冲它的一部分,发送其大小和相应的块,然后在主体发送完之前重复这个过程。服务器可以用大小为0的块作为主体结束的信号,这样就可以继续保持连接,为下一个响应做准备。来看看一个分块编码的报文示例:

12.5多部分媒体类型

MIME中的multipart(多部分)电子邮件报文中包含多个报文,它们合在一起作为单一的复杂报文发送。每一部分都是独立的,有各自的描述其内容的集,不同部分之间用分界字符串连接在一起。相应得,HTTP协议中也采纳了多部分对象集合,发送的一份报文主体内可包含多种类型实体。多部分对象集合包含的对象如下:

multipart/form-data:在Web表单文件上传时使用;multipart/byteranges:状态码PartialContent响应报文包含了多个范围的内容时使用。

12.6范围请求

假设你正在下载一个很大的文件,已经下了四分之三,忽然网络中断了,那下载就必须重头再来一遍。为了解决这个问题,需要一种可恢复的机制,即能从之前下载中断处恢复下载。要实现该功能,这就要用到范围请求。有了范围请求,HTTP客户端可以通过请求曾获取失败的实体的一个范围(或者说一部分),来恢复下载该实体。当然这有一个前提,那就是从客户端上一次请求该实体到这一次发出范围请求的时间段内,该对象没有改变过。例如:

GET/bigfile.htmlHTTP/1.1

Host:[url=

分享 转发
TOP
发新话题 回复该主题