要想展示一个网站,首先得有展示的数据,我们就看看服务器上的文件是如何被传输到浏览器的。
先从一些概念说起。
数据包
简单来说,你上网打开网页,就是你先发送数据包给网站,它接收到了之后,根据你发送的数据包的IP地址,返回给你网页的数据包,也就是说,网页的浏览,实际上就是数据包的交换。
在包交换网络里,单个消息被划分为多个数据块,这些数据块被成为包,它包含发送者和接受者的地址信息。这些包沿着不同的路径在一个或多个网络中传输,并在目的地重新组合。
包是TCP/IP协议通信传输中的数据单位。
数据包的结构如下:
详细结构解释,点击查看
网络协议
互联网进行通信时,需要相应的网络协议,TCP/IP 就是为使用互联网而开发制定的协议族。
网际协议
数据包要在互联网上传输,就要符合 网际协议 (Internet Protocol,简称IP)标准。互联网上不同的在线设备都有唯一的地址,地址只是一个数字。
计算机的地址就称为IP地址,访问任何网站实际上只是你的计算机向另一台计算机请求信息。
要想把一个数据包从主机A发送给主机B,在传输之前,数据包上会被附加上主机B的IP地址信息,这样在传输过程中才能正确寻址(收货人地址)。额外的,数据包上还会附加主机A本身的IP地址(发货人地址),有了这些信息主机B才能回复信息给主机A。这些信息会被装进一个叫 IP头 的数据结构里。IP头是IP数据包开头的信息,包含IP版本、源IP地址、目标地址、生存时间等信息。
一个数据包从主机A到主机B的简化过程大概为:
- 主机A将数据包交给网络层
- 网络层将IP头附加到数据包上,组成新的 IP数据包,并交给下一层
- 通过物理网络将数据包传输给主机B
- 数据包被传输到主机B的网络层,主机B拆开数据包的IP头信息,将拆开的数据部分交给上层
- 最终,数据包就到达了主机B
UDP
IP是非常底层的协议,只负责把数据包传送到对方电脑,但是对方电脑并不知道把数据包交给哪个程序,因此,需要基于IP之上开发能和应用打交道的协议,最常见的是 用户数据包协议 (User Datagram Protocol),简称UDP。
UDP中一个最重要的信息是端口号,端口号其实就是一个数字,每个想访问网络的程序都需要绑定一个端口号。通过端口号就能把指定的数据包发给指定的程序了。
IP通过IP地址信息把数据包发送给指定的电脑,而UDP通过端口号把数据包分发给正确的程序。
和IP头一样,端口号会被装进UDP头里面,UDP头再和原始数据包合并组成新的UDP数据包。UDP头中除了目的端口,还有源端口号等信息。
此时,数据包的旅程将会增加两步
- 主机A将数据包交给网络层
- 传输层会在数据包前面附加上UDP头,组成新的UDP数据包,将新的UDP数据包交给网络层
- 网络层将IP头附加到数据包上,组成新的 IP数据包,并交给下一层
- 通过物理网络将数据包传输给主机B
- 数据包被传输到主机B的网络层,主机B拆开数据包的IP头信息,将拆开的数据部分交给上层
- 在传输层,数据包中的UDP头被拆开,并根据UDP中所提供的端口号,把数据部分交给上层的应用程序
- 最终,数据包就到达了主机B上层应用程序
TCP
对于浏览器请求,或者邮件这类要求数据传输可靠性的应用,如果使用UDP来传输会存在两个问题:
- 数据包在传输的过程中容易丢失;
- 大文件会被拆分成很多小的数据包来传输,这些小的数据包会经过不同的路由,并在不同时间到达接收端,而UDP协议并不知道如何组装这些数据包,从而把数据包还原成完整的文件。
基于这两个问题,我们引入了 TCP(Transmission Control Protocol,传输控制协议)。相对于UDP有下面两个特点:
- 对于数据包丢失的情况,TCP提供重传机制;
- 引入了数据包排序机制,用来保证把乱序的数据包组合成一个完整的文件。
和UDP头一样,TCP头除了包含目标端口和本机端口号之外,还提供了用于排序的序列号,以便接收端排序。
TCP的连接过程
一个完整的TCP连接的生命周期包括 建立连接、传输数据、断开连接。
- 建立连接:通过“三次握手”来建立客户端和服务器之间的连接。在建立一个TCP连接时,客户端和服务器总共要发送三个数据包以确认连接的建立。
大概流程如下:
- (SYN=1, seq=x):
客户端发送一个TCP的SYN标志位置1的包,指明客户端打算连接的服务器端口,以及初始序号X,保存在包头的序列号字段里,发送完毕后,客户端进入SYN_SEND
状态。 - (SYN=1,ACK=1,seq=y,ACKnum=x+1):
服务器发回确认包(ACK)应答。即SYN标志位和ACK标志位均为1.服务器选择自己ISN序列号,放到Seq域里,同时将确认序列号(Acknowledgement Number)设置为客户端的ISN+1,即X+1。发送完毕后,服务器端进入SYN_RCVD
状态。 - (ACK=1,ACKnum=y+1):
客户端再次发送确认包(ACK),SYN标志位为1,并且把服务器发来的ACK的序号字段+1,放在确认字段中发送给对方,并且在数据段放写的+1
发送完毕后,客户端进入ESTABLISHED
状态,当服务器接收到这个包时,也进入ESTABLISHED
状态,TCP握手结束。
数据传输阶段:在该阶段,接收端需要对每个数据包进行确认操作,在接收到数据包后,需要发送 确认数据包 给发送端。当发送端发送了一个数据包之后,在规定时间内没有收到接收端反馈的确认消息,则判断数据包丢失,触发重传机制。数据包到达接收端后,会按照TCP头中的序号为其排序,从而保证数据完整。
断开连接阶段:数据传输完毕后,要终止连接,“四次挥手”保证双方都能断开连接。
大概流程如下:
中断连接端可以是客户端,也可以是服务器端。
- 客户端发送一个FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入FIN_WAIT_1状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
- 服务器端收到FIN后,先发送ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入FIN_WAIT_2 状态,继续等待服务器端的FIN报文。
- 当服务器端确定数据已发送完成,则向客户端发送FIN=N报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入LAST_ACK状态。
- 客户端收到FIN=N报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送ack=N+1后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。服务器端收到ACK后,就知道可以断开连接了。客户端等待了2MSL后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。
上面是一方主动关闭,另一方被动关闭的情况,实际中还会出现同时发起主动关闭的情况,
具体流程如下图:
HTTP
HTTP协议(HyperText Transfer Protocol, 超文本传输协议)是基于TCP/IP协议的应用层协议。它不涉及数据包的传输,主要规定了客户端和服务器之间的通信格式。默认使用80端口,是浏览器使用最广的协议。我们平时工作中最直接能看到的就是HTTP协议。
通信流程
利用TCP/IP协议族进行网络通信时,会通过分层顺序与对方进行通信。发送端从应用层往下走,接收端则从链路层往上走,如下:
- 作为发送端的客户端在应用层(HTTP协议)发出一个想看某个Web页面的HTTP请求。
- 为了传输方便,在传输层(TCP协议)把从应用层收到的数据(HTTP请求报文)进行分割,并在各个报文上打上标记序号以及端口号转发给网络层。
- 在网络层(IP协议),增加作为通信目的地的MAC地址后转发给链路层。这样,通信请求就准备齐全了。
- 接收端的服务器在链路层接收到数据,按序往上层发送,一直到应用层。当传输到应用层,才能算真正接收到由客户端发送过来的HTTP请求。
如下图所示:
HTTP协议基础
- 通过请求和响应的交换达成通信
应用HTTP协议时,必定是一端担任客户端角色,另一端担任服务端角色。也就是说,一定是从客户端开始建立通信,服务端在没有接收到请求之前不会发送响应
- HTTP是无状态的协议
协议自身不对请求和响应之间的通信状态进行保存。这是为了更快的处理大量事务,确保协议的可伸缩性,而特意把HTTP协议设计的如此简单。
- 使用Cookie做状态管理
通过在请求和响应报文中写入Cookie信息来控制客户端的状态。根据从服务端发送的响应报文内一个叫Set-Cookie的首部字段信息。通知客户端保存Cookie。当下次客户端再发送请求,会自动在请求报文中加入Cookie的值发送出去。服务端接收到之后,对比服务器上的记录,就能得到之前的状态信息。
使用URI定位资源
告知服务器意图的HTTP方法
HTTP报文结构
用于 HTTP 协议交互的信息被称为 HTTP 报文。请求端(客户端)的 HTTP 报文叫做请求报文;响应端(服务器端)的叫做响应报文。HTTP 报文本身是由多行(用 CR+LF 作换行符)数据构成的字符串文本。
HTTP 报文大致可分为报文首部和报文主体两部分。两者由最初出现的空行(CR+LF)来划分。通常,并不一定有报文主体。如下:
请求报文示例:
响应报文示例:
总结
本文只是对各个协议做了一个基础概念的梳理,关于协议的具体细节还有很多。大概了解了数据是如何相互传递的,通过IP协议使数据可以到达目标主机,通过UDP/TCP协议使数据包能找到主机对应的程序,使用HTTP协议在应用层对数据处理,最终实现了传输数据的目的。这就是我们能够使用浏览器查看网页的基础,有了数据包的传输,才能看到各种各样的网页。