在网络传输过程中,TCP/IP协议起了非常重要的作用,那么,TCP/IP协议具体是什么呢?
TCP/IP(传输控制协议/互联网协议)是一组特别的协议,其子协议包括TCP、IP、UDP、ARP等。在网络通信的过程中,将发出数据的主机称为源主机,将接收数据的主机称为目的主机。当源主机发出数据时,数据在源主机中从上层向下层传送。源主机中的应用进程先将数据交给应用层,应用层在数据中加上必要的控制信息就成了报文流,报文流向下传给传输层。传输层在收到的数据单元中加上本层的控制信息,就形成了报文段、数据报,再将报文段、数据段交给网络层。网络层在报文段、数据段中加上本层的控制信息,就形成了IP数据报,并将其传给网络接口。网络接口将网络层发来的IP数据报组装成帧,并以比特流的形式传给网络硬件(即物理层),数据离开源主机。
通过网络传输,数据到达目的主机后,按照与源主机相反的过程,在目的主机中从下层向上层进行拆包传送。首先由网络接口层接收数据,依次剥离原来加上的控制信息,最后将源主机中的应用进程发送的数据交给目的主机的应用进程。
TCP/IP协议的基本传输单位是数据报。TCP协议负责把数据分成若干个数据报,并给每个数据报加上报头,报头上有编号,以保证目的主机能将数据还原为原来的格式。IP协议在每个报头上再加上接收端主机IP地址,这样数据就能找到自己要去的地址。如果传输过程中出现数据失真、数据丢失等情况,TCP协议会自动请求重新传输数据,并重组数据报。可以说,IP协议用于保证数据的传输,TCP协议用于保证数据传输的质量。TCP/IP协议在数据传输时每通过一层就要在数据上加个报头,其中的数据供接收端同一层协议使用,而在接收端,每经过一层要把用过的报头去掉,这样可以保证传输数据的一致性。
在计算机网络中,实际应用的网络协议是TCP/IP协议族,其中,TCP/IP协议的应用层大体对应OSI/RM模型的应用层、表示层和会话层,TCP/IP协议的网络接口层对应OSI/RM模型的数据链路层和物理层。TCP/IP包含以下4层:
(1)IP协议
IP协议是网络层中最重要的协议,IP层接收由更低层(网络接口层,例如以太网设备驱动程序)发来的数据包,并把该数据包发送到更高层——TCP或UDP层;同时,IP层也把从TCP或UDP层接收的数据包传送到更低层。IP数据包是不可靠的,因为IP并没有做任何事情来确认数据包是否按顺序发送或者是否被破坏。IP数据包中含有发送它的主机的地址(源地址)和接收它的主机的地址(目的地址)。高层的TCP和UDP服务在接收数据包时,通常假设包中的源地址是有效的。也可以这样说,IP地址形成了许多服务的认证基础,这些服务相信数据包是从一个有效的主机发送来的。IP确认包含一个选项,叫作IPsource routing,它可以用来指定一条源地址和目的地址之间的直接路径。对于一些TCP和UDP的服务来说,使用了该选项的IP包好像是从路径上的最后一个系统传递过来的,而不是来自它的真实地点。这个选项是为了测试而存在的,说明它可以欺骗系统来进行平时被禁止的连接。因此,许多依靠IP源地址做确认的服务将产生问题并且会被非法入侵。
(2)UDP协议
UDP与TCP位于同一层,UDP主要用于那些面向查询—应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网络时间协议)和DNS(DNS也使用TCP)。
(3)ARP协议
APR协议又称地址解析协议,是一个根据IP地址获取物理地址的TCP/IP协议。主机和主机间的通信在物理上类似于网卡和网卡间的通信,目前网卡会根据MAC地址进行识别,实现主机和主机间的通信,需要知道与对方主机的IP地址对应的MAC地址,APR协议能很好处理。处理过程如下:主机发送信息时将包含目标IP地址的ARP请求广播到局域网络上的所有主机,并接收返回消息,以此确定目标的物理地址。收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。ARP命令可用于查询本机ARP缓存中IP地址和MAC地址的对应关系,添加或删除静态对应关系等。
互联网网络传输基于TCP协议传输,TCP三次握手过程,如图3-1所示。
图3-1 TCP三次握手交互图
注意,第1次SYN是请求建立连接,并在其序列号的字段进行序列号的初始值设定。建立连接,设置为1。ACK是确认号是否有效,一般置为1。
第一次握手:建立连接时,客户端发送SYN包(SYN=1)到服务器,并进入SYN_SENT状态,等待服务器确认。SYN是同步序列编号(Synchronize Sequence Number)。
第二次握手:服务器收到SYN包,必须确认客户的SYN(ack= x +1),同时自己也发送一个SYN包(SYN=1),即SYN+ACK包,此时服务器进入SYN_RECV状态。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack= y +1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
网络传输完毕后,客户端进程发出连接释放报文,并且停止发送数据。此时会经过TCP四次挥手,其过程如图3-2所示。
图3-2 TCP四次挥手交互图
注意,第1次FIN是希望断开连接,一般置FIN为1。挥手处理过程如下。
1)客户端进程发出连接释放报文,并且停止发送数据,释放数据报文首部,FIN=1,序列号为seq= u ,TCP规定FIN报文段不携带数据也要消耗一个序号。
2)服务器接收到连接释放报文,发出确认报文,ACK=1,ack= u +1,并且带上自身序列号seq= v ,服务端进入CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端没有数据要发送,但是服务器若发送数据,客户端依然要接收。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
3)收到服务器的确认请求后,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接收服务器发送的最后的数据)。
4)服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack= u +1,由于处于半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq= w ,那么服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
5)客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack= w +1,而自己的序列号是seq= u +1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
6)服务器只要收到了客户端发出的确认信息,就会立即进入CLOSED状态,同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
互联网中Web请求过程如图3-3所示。
图3-3 Web请求过程图
注意,输入URL地址或点击URL链接后,浏览器打开呈现的请求过程具体分为以下步骤。
1)查找DNS,解析出与URL对应的IP地址(公网IP)。
2)初始化网络连接(包括TCP三次握手)。
3)发送HTTP请求。
4)通过网络传输请求到服务器。
5)Web服务器接收请求,经过处理转发到Web应用。
6)Web应用处理请求,如MVC框架,返回内容。
7)通过网络传输应答内容到前端浏览器。
8)浏览器解析从服务器返回的应答内容,并开始渲染和绘制。
9)根据HTML内容来构建DOM(文档对象模型)。
10)加载和解析样式,构建CSSOM(CSS对象模型)。
11)根据DOM和CSSOM来构建渲染树,按照文档顺序从上到下依次进行。
12)根据渲染树的过程,适当把已经构建好的部分绘制到界面上,中间会伴随着重绘和回流,循环操作,直到渲染绘制完成。
13)整个页面加载完成,触发OnLoad事件。
详细流程分析如下。
1)要通过URL将请求发送到服务器,浏览器就要知道这个URL对应的IP是什么,只有知道了IP地址,浏览器才能将请求发送到指定服务器的具体IP和端口。浏览器的DNS解析器负责把URL解析为正确的IP地址,这个解析很花时间,而且在解析过程中,浏览器不能从服务器那里下载任何东西。浏览器和操作系统提供了DNS解析缓存支持。
2)获取IP之后,浏览器会请求与服务器建立连接,TCP经过3次握手后建立连接通道。
3)浏览器真实发送HTTP请求,发送请求报文,包含请求行(包含请求方法、URI、HTTP版本信息;请求首部字段)、请求内容实体、空行。
4)网络开始传输请求到服务器,这个会包含很多时间,如网络阻塞时间、网络延迟时间、真正传输内容时间等。
5)Web服务器收到请求,会根据URL上下文转交给相应Web应用进行处理。
6)Web应用会进行很多处理,如filter、aop前置处理、IOC处理、创建对象,处理后会生成Response对象。熟悉Spring的读者对此过程会更清晰。
7)返回HTTP响应报文,包含状态行(包含HTTP版本、状态码、状态码的原因短语)、响应首部字段、响应内容实体、空行。
8)通过网络将应答内容传送回前端浏览器,先返回HTML代码,不包含图片、外部脚本、CSS等。
9)在浏览器解析页面进行渲染和绘制,具体过程如下:
a)装载和解析HTML文档,构建DOM,如果在解析过程中发现需要其他资源,如图片,浏览器会发出获取资源的请求;
b)装载和解析CSS,构建cssom;
c)根据DOM和cssom构建渲染树;
d)对渲染树节点进行布局处理,确认其屏幕位置;
e)将渲染好的节点绘制到界面上,渲染引擎不会等到所有HTML都解析完后才创建布局渲染树,而是在处理解析渲染树的同时向后端请求资源。