计算机网络

一.网络

OSI七层网络模型

网络的七层架构从下到上主要包括物理层、数据链路层、网络层、传输层、会话层表示层和应用层,如图所示。
物理层主要定义物理设备标准,它的主要作用是传输比特流,具体做法是在发送端将1、0转化为电流强弱来进行传输,在到达目的地后再将电流强弱转化为1、0,也就是我们常说的模数转换与数模转换,这一层的数据叫作比特。
数据链路层主要用于对数据包中的MAC地址进行解析和封装。这一层的数据叫作帧。在这一层工作的设备是网卡、网桥、交换机。
网络层主要用于对数据包中的IP地址进行封装和解析,这一层的数据叫作数包。在这一层工作的设备有路由器、交换机、防火墙等。
传输层定义了传输数据的协议和端口号,主要用于数据的分段、传输和重组。这一层工作的协议有TCP和UDP等。TCP是传输控制协议,传输效率低,可靠性强,用于传输对可靠性要求高、数据量大的数据,比如支付宝转账使用的就是TCP;UDP是用户数据报协议,与TCP的特性恰恰相反,用于传输可靠性要求不高、数据量小的数据,例如抖音等视频服务就使用了UDP。
会话层在传输层的基础上建立连接和管理会话,具体包括登录验证、断点续传、数据粘包与分包等。在设备之间需要互相识别的可以是IP,也可以是MAC或者主机名。
表示层主要对接收的数据进行解释、加密、解密、压缩、解压缩等,即把计算机能够识别的内容转换成人能够识别的内容(图片、声音、文字等)。
应用层基于网络构建具体应用,例如FTP文件上传下载服务、 Telnet服务、HTTP服务、DNs服务、SNMP邮件服务等。
 在这里插入图片描述

TCP/IP四层网络模型

TCP/IP不是指TCP和IP这两个协议的合称,而是指因特网的整个TCP/IP协议簇。从协议分层模型方面来讲,TCP/IP由4个层次组成:网络接口层、网络层、传输层和应用层。
在这里插入图片描述
TCP/IP中网络接口层、网络层、传输层和应用层的具体工作职责如下。
网络接口层( Network Access Layer)定义了主机间网络连通的协议,具体包括Ethernet、FDDI、ATM等通信协议。
网络层( Internet Layer)主要用于数据的传输、路由及地址的解析,以保障主机可以把数据发送给任何网络上的目标。数据经过网络传输,发送的顺序和到达的顺序可能发生变化。在网络层使用IP( Internet Protocol)和地址解析协议(ARP)。
传输层( Transport Layer)使源端和目的端机器上的对等实体可以基于会话相互通信。在这一层定义了两个端到端的协议TCP和UDP。TCP是面向连接的协议提供可靠的报文传输和对上层应用的连接服务,除了基本的数据传输,它还有可靠性保证、流量控制、多路复用、优先权和安全性控制等功能。UDP是面向无连接的不可靠传输的协议,主要用于不需要TCP的排序和流量控制等功能的应用程序。
应用层( Application Layer)负责具体应用层协议的定义,包括 Telnet( TELecommunications NETwork,虚拟终端协议)、FTP( File Transfer Protocol,文件传输协议)、SMTP( Simple Mail Transfer Protocol,电子邮件传输协议)DNS( Domain Name Service,域名服务)、NNTP( Net News Transfer Protocol网上新闻传输协议)和HTp( lyper Text Transfer Protocol,超文本传输协议)等。

二.ARP协议

IP地址和硬件地址

IP地址和硬件地址的区别:
长度:物理地址即硬件地址,由48bit构成;IP地址由32bit组成,是逻辑地址(IP地址是用软件实现的)。
存放位置:IP地址放在IP数据报的首部,硬件地址放在MAC帧的首部。
应用:在网络层和网络层以上使用的是IP地址,数据链路层及以下使用的是硬件地址。
在这里插入图片描述

协议内容

在实际应用中,已经知道了一个机器的IP地址,需要找出其相应的硬件地址。ARP协议是“Address Resolution Protocol”(地址解析协议)的缩写。其作用是为了从网络层使用的IP地址解析出在数据链路层使用的硬件地址。
我们知道,网络层使用的是IP地址,但在实际网络的链路上传送数据帧时,最终还是必须使用该网络的硬件地址。但IP地址和下面的网络的硬件地址之间由于格式不存在简单的映射关系(例如,IP地址有32位,而局域网的硬件地址是48位)此外网络上可能经常会有新的主机加入进来,或撤走一些主机更换网络适配器也会使主机的硬件地址改变。地址解析协议ARP解决这个问题的方法是在主机ARP高速缓存中应存放一个从IP地址到硬件地址的映射表,并且这个映射表还经常动态更新(新增或超时删除)。
注意:ARP是解决同一个局域网上的主机或路由器的IP地址和硬件地址的映射问题,如果所要找的主机与源主机不在同一个局域网上,就需要借助路由器交付。
为什么不直接用硬件地址通信,而是用IP地址?
全世界存在各式各样的网络,它们使用不同的硬件地址,要使这些异构网络能够通信就必须进行非常复杂的硬件地址转换工作,单凭用户和用户主机来完成这项工作几乎不可能。因此依靠统一的IP地址,把调用ARP的复杂过程交由计算机软件自动进行,对用户带来极大方便。

三.IP/ICMP协议

IP协议

IP是面向无连接、无状态的,没有额外的机制保证发送的包是否有序到达。IP首先规定出IP地址格式,该地址相当于在逻辑意义上进行了网段的划分,给每台计算机额外设置了一个唯一的详细地址。既然链路层可以通过唯一的MAC地址找到机器,为什么还需要通过唯一的IP地址再来标识呢?简单来说,在世界范围内,不可能通过广播的方式,从数以万计的计算机找到目标MAC地址的计算机而不超时。
在这里插入图片描述
版本:
该字段包含的是IP的版本号,4比特。目前IP的版本为4(即IPv4),现在无论是在局域网还是在广域网中,使用的都是IPv4。目前IPv4所面临的最大问题是IP地址空间不足,即使使用的IPv6是IP的下一个版本,但也不能解决IP地址缺乏的问题。
首部长度:
该字段用于表示IP数据包头长度,4比特。IP数据包头最短为20字节,但是其长度是可变的,具体长度取决于可选字段的长度。
优先级与服务类型:
该字段用于表示数据包的优先级和服务类型,8比特。用来区分哪些数据包优先级高和哪些数据优先级低。例:同时迅雷下载和聊QQ,其中QQ的优先级就比迅雷下载的优先级高,否则就需要等待迅雷下载完毕才能进行QQ聊天。
总长度:
该字段用以指示整个IP数据包的长度,16比特。最长为65535(2^16-1)字节,包括包头和数据。
标识符:
该字段用于表示IP数据包的标识符,16比特。当IP对上层数据分片时,它将给所有的分片分配一组编号,然后将这些编号放入标识符字段中,保证分片不会被错误的重组。标识符字段用于标识一个数据包,以便接收节点可以重组被分片的数据包。
标志
标志字段,3比特。标志和分片一起被用来传递信息。例如,当数据包从一个以太网发送到另一个以太网时,指示对当前的包不能进行分片或者一个包被分片后指示在一系列的分片中最后一个分片是否已发出。
段偏移量:
该字段用于表示段偏移量,13比特。段偏移量中包含的信息是在一个分片序列中如何将分片重新连接起来。
TTL
该字段用于表示IP数据包的生命周期,8比特。该字段包含的信息可以防止一个数据包在网络中无限循环的转发下去。即防止路由环路。
TTL值的意义是一个数据包在被抛弃前在网络中可以经历的最大周转时间。数据包经过的每一个路由器都会检查该字段中的值,当TTL的值为0时,数据包将被丢弃。
TTL对应一个数据包通过路由器的数目。一个数据包经过每一个路由器,TTL将减去1。
协议号:
协议字段,8比特。该字段用以指示在IP数据包中封装的是哪一个协议,是TCP还是UDP,TCP的协议号为6,UDP的协议号为17.
首部校验和:
该字段用于表示校验和,16比特。校验和是16位的错误检测字段。目的主机和网络中的每个网关都要重新计算包头的校验和,就如同源主机做的一样。如果数据包没有被改动过,两个计算结果应该是一样的。
源IP地址:
该字段用于表示数据包的源地址,32比特。这是一个网络地址,指的是发送该数据包设备的网络地址。
目标IP地址:
该字段用于表示数据包的目的地址,32比特。这也是一个网络地址,但指的是接收节点的网络地址。
可选项:
可选项字段根据实际情况可变长,可以和IP一起使用的选项有多个。例如,可以输入创建该数据包的时间等。
数据
上层数据(TCP报文或UDP报文)。

ICMP协议

网际控制报文协议ICMP(Internet Control Message Protocol)。它允许主机或者路由器报告差错情况和提供有关异常情况的报告。也就是说 ICMP 协议就是为了更高效的转发 IP数据报和提高交付成功的机会。
ICMP协议的数据格式
在这里插入图片描述
根据上图我们知道了 ICMP协议头包含 4个字节,头部主要用来说明类型和校验 ICMP报文。下图是对应的类型和代码释义列表,我们后面分析抓包的时候会用到。
在这里插入图片描述
Ping过程解析
了解了上面的基础概念后,我们来分析下抓包的数据,其流程如下:
A 电脑( 192.168.2.135)发起 ping请求, ping192.168.2.179
A 电脑广播发起 ARP请求,查询 192.168.2.179的 MAC地址。
B 电脑应答 ARP请求,向 A电脑发起单向应答,告诉 A电脑自己的 MAC地址为 90:A4:DE:C2:DF:FE
知道了 MAC地址后,开始进行真正的 ping请求,由于 B电脑可以根据A电脑发送的请求知道 源 MAC地址,所以就可以根据源 MAC地址进行响应了。
上面的请求过程我画成流程图比较直观一点:
在这里插入图片描述

四.TCP/UDP协议

网络层只把分组发送到目的主机,但是真正通信的并不是主机而是主机中的进程。传输层提供了进程间的逻辑通信,传输层向高层用户屏蔽了下面网络层的核心细节,使应用程序看起来像是在两个传输层实体之间有一条端到端的逻辑通信信道。

UDP 和 TCP 的特点与区别

用户数据报协议 UDP(User Datagram Protocol)
是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信。

传输控制协议 TCP(Transmission Control Protocol)
是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一)。

UDP 、TCP 首部格式

在这里插入图片描述
UDP 首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。
在这里插入图片描述
TCP 首部格式比 UDP 复杂。
序号:用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。

确认号:期望收到的下一个报文段的序号。例如 B 正确收到 A 发送来的一个报文段,序号为 501,携带的数据长度为 200 字节,因此 B 期望下一个报文段的序号为 701,B 发送给 A 的确认报文段中确认号就为 701。

数据偏移:指的是数据部分距离报文段起始处的偏移量,实际上指的是首部的长度。

控制位:八位从左到右分别是 CWR,ECE,URG,ACK,PSH,RST,SYN,FIN。

CWR:CWR 标志与后面的 ECE 标志都用于 IP 首部的 ECN 字段,ECE 标志为 1 时,则通知对方已将拥塞窗口缩小;

ECE:若其值为 1 则会通知对方,从对方到这边的网络有阻塞。在收到数据包的 IP 首部中 ECN 为 1 时将 TCP 首部中的 ECE 设为 1;
URG:该位设为 1,表示包中有需要紧急处理的数据,对于需要紧急处理的数据,与后面的紧急指针有关;

ACK:该位设为 1,确认应答的字段有效,TCP规定除了最初建立连接时的 SYN 包之外该位必须设为 1;

PSH:该位设为 1,表示需要将收到的数据立刻传给上层应用协议,若设为 0,则先将数据进行缓存;

RST:该位设为 1,表示 TCP 连接出现异常必须强制断开连接;

SYN:用于建立连接,该位设为 1,表示希望建立连接,并在其序列号的字段进行序列号初值设定;

FIN:该位设为 1,表示今后不再有数据发送,希望断开连接。当通信结束希望断开连接时,通信双方的主机之间就可以相互交换 FIN 位置为 1 的 TCP 段。

每个主机又对对方的 FIN 包进行确认应答之后可以断开连接。不过,主机收到 FIN 设置为 1 的 TCP 段之后不必马上回复一个 FIN 包,而是可以等到缓冲区中的所有数据都因为已成功发送而被自动删除之后再发 FIN 包;

窗口:窗口值作为接收方让发送方设置其发送窗口的依据。之所以要有这个限制,是因为接收方的数据缓存空间是有限的。

TCP的三次握手

在这里插入图片描述
假设 A 为客户端,B 为服务器端。
首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
• A 向 B 发送连接请求报文,SYN=1,ACK=0,选择一个初始的序号 x。
• B 收到连接请求报文,如果同意建立连接,则向 A 发送连接确认报文,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
• A 收到 B 的连接确认报文后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
B 收到 A 的确认后,连接建立。
为什么三次?

1、第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。
2、换个易于理解的视角来看为什么要 3 次握手。

客户端和服务端通信前要进行连接,“3次握手”的作用就是双方都能明确自己和对方的收、发能力是正常的。
第一次握手:客户端发送网络包,服务端收到了。这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。

第二次握手:服务端发包,客户端收到了。这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。从客户端的视角来看,我接到了服务端发送过来的响应数据包,说明服务端接收到了我在第一次握手时发送的网络包,并且成功发送了响应数据包,这就说明,服务端的接收、发送能力正常。而另一方面,我收到了服务端的响应数据包,说明我第一次发送的网络包成功到达服务端,这样,我自己的发送和接收能力也是正常的。
第三次握手:客户端发包,服务端收到了。这样服务端就能得出结论:客户端的接收、发送能力,服务端的发送、接收能力是正常的。第一、二次握手后,服务端并不知道客户端的接收能力以及自己的发送能力是否正常。
而在第三次握手时,服务端收到了客户端对第二次握手作的回应。从服务端的角度,我在第二次握手时的响应数据发送出去了,客户端接收到了。所以,我的发送能力是正常的。而客户端的接收能力也是正常的。
经历了上面的三次握手过程,客户端和服务端都确认了自己的接收、发送能力是正常的。之后就可以正常通信了。
每次都是接收到数据包的一方可以得到一些结论,发送的一方其实没有任何头绪。我虽然有发包的动作,但是我怎么知道我有没有发出去,而对方有没有接收到呢?
而从上面的过程可以看到,最少是需要三次握手过程的。两次达不到让双方都得出自己、对方的接收、发送能力都正常的结论。
其实每次收到网络包的一方至少是可以得到:对方的发送、我方的接收是正常的。而每一步都是有关联的,下一次的“响应”是由于第一次的“请求”触发,因此每次握手其实是可以得到额外的结论的。
比如第三次握手时,服务端收到数据包,表明看服务端只能得到客户端的发送能力、服务端的接收能力是正常的,但是结合第二次,说明服务端在第二次发送的响应包,客户端接收到了,并且作出了响应,从而得到额外的结论:客户端的接收、服务端的发送是正常的。

TCP的四次挥手(为什么四次?)

在这里插入图片描述
• 客户端发送一个 FIN 段,并包含一个希望接收者看到的自己当前的序列号 K. 同时还包含一个 ACK 表示确认对方最近一次发过来的数据。
• 服务端将 K 值加 1 作为 ACK 序号值,表明收到了上一个包。这时上层的应用程序会被告知另一端发起了关闭操作,通常这将引起应用程序发起自己的关闭操作。
• 服务端发起自己的 FIN 段,ACK=K+1, Seq=L。
• 客户端确认。进入 TIME-WAIT 状态,等待 2 MSL(最大报文存活时间)后释放连接。ACK=L+1。
为什么建立连接是三次握手,而关闭连接却是四次挥手呢?
1、TCP连接是双向传输的对等的模式,就是说双方都可以同时向对方发送或接收数据。当有一方要关闭连接时,会发送指令告知对方,我要关闭连接了。
2、这时对方会回一个ACK,此时一个方向的连接关闭。但是另一个方向仍然可以继续传输数据,也就是说,服务端收到客户端的 FIN 标志,知道客户端想要断开这次连接了,但是,我服务端,我还想发数据呢?我等到发送完了所有的数据后,会发送一个 FIN 段来关闭此方向上的连接。接收方发送 ACK确认关闭连接。

注意,接收到FIN报文的一方只能回复一个ACK, 它是无法马上返回对方一个FIN报文段的,因为结束数据传输的“指令”是上层应用层给出的,我只是一个“搬运工”,我无法了解“上层的意志”。

3、客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

4、因为服务端在 LISTEN 状态下,收到建立连接请求的 SYN 报文后,把 ACK 和 SYN 放在一个报文里发送给客户端。而关闭连接时,当收到对方的 FIN 报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方是否现在关闭发送数据通道,需要上层应用来决定,因此,己方 ACK 和 FIN 一般都会分开发。

TIME_WAIT
客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:

• 确保最后一个确认报文能够到达。如果 B 没收到 A 发送来的确认报文,那么就会重新发送连接释放请求报文,A 等待一段时间就是为了处理这种情况的发生。
• 等待一段时间是为了让本连接持续时间内所产生的所有报文都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文。

TCP 短连接和长连接的区别

短连接:Client 向 Server 发送消息,Server 回应 Client,然后一次读写就完成了,这时候双方任何一个都可以发起 close 操作,不过一般都是 Client 先发起 close 操作。短连接一般只会在 Client/Server 间传递一次读写操作。
短连接的优点:管理起来比较简单,建立存在的连接都是有用的连接,不需要额外的控制手段。

长连接:Client 与 Server 完成一次读写之后,它们之间的连接并不会主动关闭,后续的读写操作会继续使用这个连接。
在长连接的应用场景下,Client 端一般不会主动关闭它们之间的连接,Client 与 Server 之间的连接如果一直不关闭的话,随着客户端连接越来越多,Server 压力也越来越大,这时候 Server 端需要采取一些策略,如关闭一些长时间没有读写事件发生的连接,这样可以避免一些恶意连接导致 Server 端服务受损;如果条件再允许可以以客户端为颗粒度,限制每个客户端的最大长连接数,从而避免某个客户端连累后端的服务。
长连接和短连接的产生在于 Client 和 Server 采取的关闭策略,具体的应用场景采用具体的策略。

TCP粘包、拆包及解决办法

为什么常说 TCP 有粘包和拆包的问题而不说 UDP ?
由前两节可知,UDP 是基于报文发送的,UDP首部采用了 16bit 来指示 UDP 数据报文的长度,因此在应用层能很好的将不同的数据报文区分开,从而避免粘包和拆包的问题。

而 TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 并没有把这些数据块区分边界,仅仅是一连串没有结构的字节流;另外从 TCP 的帧结构也可以看出,在 TCP 的首部没有表示数据长度的字段,基于上面两点,在使用 TCP 传输数据时,才有粘包或者拆包现象发生的可能。

什么是粘包、拆包?
假设 Client 向 Server 连续发送了两个数据包,用 packet1 和 packet2 来表示,那么服务端收到的数据可以分为三种情况,现列举如下:

第一种情况,接收端正常收到两个数据包,即没有发生拆包和粘包的现象。
在这里插入图片描述
第二种情况,接收端只收到一个数据包,但是这一个数据包中包含了发送端发送的两个数据包的信息,这种现象即为粘包。这种情况由于接收端不知道这两个数据包的界限,所以对于接收端来说很难处理。
在这里插入图片描述
第三种情况,这种情况有两种表现形式,如下图。接收端收到了两个数据包,但是这两个数据包要么是不完整的,要么就是多出来一块,这种情况即发生了拆包和粘包。这两种情况如果不加特殊处理,对于接收端同样是不好处理的。
在这里插入图片描述
在这里插入图片描述
为什么会发生 TCP 粘包、拆包?
• 要发送的数据大于 TCP 发送缓冲区剩余空间大小,将会发生拆包。
• 待发送数据大于 MSS(最大报文长度),TCP 在传输前将进行拆包。
• 要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
• 接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
粘包、拆包解决办法
由于 TCP 本身是面向字节流的,无法理解上层的业务数据,所以在底层是无法保证数据包不被拆分和重组的,这个问题只能通过上层的应用协议栈设计来解决,根据业界的主流协议的解决方案,归纳如下:
• 消息定长:发送端将每个数据包封装为固定长度(不够的可以通过补 0 填充),这样接收端每次接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
• 设置消息边界:服务端从网络流中按消息边界分离出消息内容。在包尾增加回车换行符进行分割,例如 FTP 协议。
• 将消息分为消息头和消息体:消息头中包含表示消息总长度(或者消息体长度)的字段。
• 更复杂的应用层协议比如 Netty 中实现的一些协议都对粘包、拆包做了很好的处理。

TCP流量控制

流量控制是为了控制发送方发送速率,保证接收方来得及接收。
接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。
实际上,为了避免此问题的产生,发送端主机会时不时的发送一个叫做窗口探测的数据段,此数据段仅包含一个字节来获取最新的窗口大小信息。

TCP拥塞控制

如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接收,而拥塞控制是为了降低整个网络的拥塞程度。
在这里插入图片描述
TCP 主要通过四个算法来进行拥塞控制:
慢开始、拥塞避免、快重传、快恢复。

发送方需要维护一个叫做拥塞窗口(cwnd)的状态变量,注意拥塞窗口与发送方窗口的区别:拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。

为了便于讨论,做如下假设:
• 接收方有足够大的接收缓存,因此不会发生流量控制;
• 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。
在这里插入图片描述
慢开始与拥塞避免

发送的最初执行慢开始,令 cwnd = 1,发送方只能发送 1 个报文段;当收到确认后,将 cwnd 加倍,因此之后发送方能够发送的报文段数量为:2、4、8 …
注意到慢开始每个轮次都将 cwnd 加倍,这样会让 cwnd 增长速度非常快,从而使得发送方发送的速度增长速度过快,网络拥塞的可能性也就更高。设置一个慢开始门限 ssthresh,当 cwnd >= ssthresh 时,进入拥塞避免,每个轮次只将 cwnd 加 1。
如果出现了超时,则令 ssthresh = cwnd / 2,然后重新执行慢开始。
快重传与快恢复
在接收方,要求每次接收到报文段都应该对最后一个已收到的有序报文段进行确认。例如已经接收到 M1 和 M2,此时收到 M4,应当发送对 M2 的确认。
在发送方,如果收到三个重复确认,那么可以知道下一个报文段丢失,此时执行快重传,立即重传下一个报文段。例如收到三个 M2,则 M3 丢失,立即重传 M3。
在这种情况下,只是丢失个别报文段,而不是网络拥塞。因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。
慢开始和快恢复的快慢指的是 cwnd 的设定值,而不是 cwnd 的增长速率。慢开始 cwnd 设定为 1,而快恢复 cwnd 设定为 ssthresh。
在这里插入图片描述

TCP协议可靠性是如何保证

TCP 是一种提供可靠性交付的协议。也就是说,通过 TCP 连接传输的数据,无差错、不丢失、不重复、并且按序到达。但是在网络中相连两端之间的介质,是复杂的,并不确保数据的可靠性交付,那么 TCP 是怎么样解决问题的?
TCP 是通过下面几个特性保证数据传输的可靠性:

  • 序列号和确认应答信号
  • 超时重发控制
  • 连接管理
  • 滑动窗口控制
  • 流量控制
  • 拥塞控制

通过序列号和确认应答信号提高可靠性

如下图,在 TCP 中,当发送端的数据到达接收主机时,接收端主机会返回一个已收到消息的通知,这个消息叫做确认应答(ACK)。当发送端将数据发出之后会等待对端的确认应答。如果有确认应答,说明数据已经成功到达对端。反之,则数据丢失的可能性很大。
在这里插入图片描述
但是,如果在一定时间内发送端都没有得到确认应答ACK,发送端就会认为数据丢失,并进行数据重发。所以,即使产生了丢包,TCP仍然能保证数据能够到达对端,实现可靠的传输。 发送端没有得到确认应答ACK的原因,主要分两种情况:
1. 发送端发送的数据丢包
在这里插入图片描述
上图中的主机A发出数据后因为网络拥堵等原因导致了丢包,数据无法达到主机B,此时,主机A如果在一个特定的时间间隔内都没收到主机B的ACK,则会将数据进行重发。
2. 接收端发送的确认应答ACK丢包或延迟
在这里插入图片描述
这个图中主机A的数据正常发送到主机B,但由于网络堵塞等原因,主机B的ACK没有达到主机A。主机A在一定时间间隔内始终没收到ACK,则会重发这个数据。此时,主机B收到数据后就会再次发送ACK,但是由于主机B已经接收过1-1000的数据,所以当再有相同数据达到它时就会放弃这个数据。

此外,也有可能因为一些其他原因导致ACK延迟到达,在源主机重发数据以后才到达的情况也屡见不鲜。此时,源主机只要按照机制重发数据即可。

虽然目标主机通过重发数据可以提供可靠的传输,但是对于目标主机来说,反复收到相同的数据可能会是一个”灾难“,既浪费网络资源,还要耗资源对它处理。所以,我们需要一种机制来识别是否已经接收到了这个数据包、又能够判断数据包是否需要接收。

目标主机反复收到相同数据是不可取的,为了保持数据的一致性,目标主机必须扔掉重复的数据包,那么怎么判断该数据包是已经重复收取过呢? 为此我们引入了序列号

序列号是按照顺序给发送数据的每一个字节(8位字节)都标上号码的编号。接收端查询接收数据 TCP 首部中的序列号和数据的长度,将自己下一步应该接收的序列号作为确认应答返送回去。通过序列号和确认应答号,TCP 能够识别是否已经接收数据,又能够判断是否需要接收,从而实现可靠传输。

所以,通过序列号,上面说的确认应答ACK处理, 重发控制,重复控制都能实现了。

超时重发控制

**重发超时是指在重发数据之前,等待确认应答到来的那个特定时间间隔。**如果超过这个时间仍未收到确认应答,发送端将进行数据重发。最理想的是,找到一个最小时间,它能保证“确认应答一定能在这个时间内返回”。

TCP 要求不论处在何种网络环境下都要提供高性能通信,并且无论网络拥堵情况发生何种变化,都必须保持这一特性。为此,它在每次发包时都会计算往返时间(RTT Round Trip Time)及其偏差(RTT波动的时间,也叫抖动)。将这个往返时间和偏差时间相加,重发超时的时间就是比这个总和要稍大一点的值。

重发超时既要考虑RTT往返时间,又要考虑网络抖动的偏差,如下图所示,网络网络环境不同可能会造成RTT大幅度摆动,TCP/IP的目的就是即使在这种环境下也能进行控制,不浪费网络流量。

在这里插入图片描述
在 BSD 的 Unix 以及 Windows 系统中,超时都以0.5秒为单位进行控制,因此重发超时都是0.5秒的整数倍。不过,最初其重发超时的默认值一般设置为6秒左右。

数据被重发之后若还是收不到确认应答,则进行再次发送。此时,等待确认应答的时间将会以2倍、4倍的指数函数延长。

此外,数据也不会被无限、反复地重发。达到一定重发次数之后,如果仍没有任何确认应答返回,就会判断为网络或对端主机发生了异常,强制关闭连接。并且通知应用通信异常强行终止。

连接管理

TCP是面向连接的通信协议,面向连接是指在数据通信之前先做好通信两端之间的准备工作。因此,在数据通信之前,会通过TCP首部发送一个SYN包作为建立连接和等待确认应答,如果对端发来确认应答ACK,则认为可以进行通信,否则如果对端没有发送正确的ACK应答,那么就不会通信。另外通信完毕需要发送FIN包来关闭连接。

滑动窗口控制

TCP是以段为单位进行数据包的发送的
在建立 TCP 连接的同时,也可以确定发送数据包的单位,我们也可以称其为**“最大消息长度”(MSS,Max Segment Size)**,也就是一个段。最理想的情况是,最大消息长度正好是 IP 中不会被分片处理的最大数据长度。

TCP 在传送大量数据时,是以 MSS 的大小将数据进行分割发送。进行重发时也是以 MSS 为单位。

MSS 在三次握手的时候,在两端主机之间被计算得出。两端的主机在发出建立连接的请求时,会在 TCP 首部中写入 MSS 选项,告诉对方自己的接口能够适应的 MSS 的大小。然后会在两者之间选择一个较小的值投入使用。
在这里插入图片描述

上图的是Tcpdump抓包的信息,在三次握手建立连接时,大家都交换了对方的MSS,目的是告诉对方,我能适应每次TCP数据传输单位最大是多少,后面通信双方就会按照这个MSS大小作为发送单位发送数据,以上图为例,TCP每次传输最多不会超过65495字节

利用滑动窗口控制提高速度
上面说了,TCP 以1个段为单位,如果每发送一个段进行一次确认应答,才能进行下一次通信,那这样的传输方式有一个缺点,就是包的往返时间(RTT)越长通信性能就越低。如下图:

在这里插入图片描述
这种方式有点类似于数据库不能并发请求,只能一个挨一个的处理,自然这样的效率肯定是比并发低的
为解决这个问题,TCP 引入了窗口这个概念。确认应答不是以每个分段来确认,而是以更大的单位进行确认,转发时间将会被大幅地缩短。也就是说,**发送端主机,在发送了一个段以后不必要一直等待确认应答,而是继续发送。**如下图所示:

在这里插入图片描述
如上图,我们假设窗口大小是4000字节,主机A可以一口气发送把4000字节的序列号发送完毕。这个跟前面每个段接收ACK后才能继续发送新一个段的情况相比,即使RTT变长也不会影响网络的吞吐量。**窗口大小就是指无需等待确认应答ACK而继续发送数据的最大值。**这种窗口机制实现了使用了大量的缓冲区(Buffer,指的是计算机存储收发数据的的内存空间),通过对多个段同时进行确认应答的功能。

滑动窗口示意图如下:
在这里插入图片描述
上面这个图一个段为1000字节,滑动窗口是4个段,在①的状态下,如果收到一个序列号为2000的ACK,那么2001 之前的数据就没必要重发了,这部分的数据可以被过滤掉,滑动窗口成为③的样子。
对于滑动窗口有以下几点特点:
上图中的窗口内的数据即便没有收到确认应答也可以被发送出去。不过,**在整个窗口的确认应答没有到达之前,如果其中部分数据出现丢包,那么发送端仍然要负责重传。**为此,发送端主机需要设置缓存保留这些待被重传的数据,直到收到他们的确认应答。
在滑动窗口以外的部分包括未发送的数据以及已经确认对端已收到的数据。当数据发出后若如期收到确认应答就可以不用再进行重发,此时数据就可以从缓存区清除。
收到确认应答的情况下,将窗口滑动到确认应答中的序列号的位置。**这样可以顺序地将多个段同时发送提高通信性能。**这种机制也别称为滑动窗口控制。

滑动窗口控制与重发控制

在使用了窗口控制中,如果出现了丢包怎么办呢?这里我们还是分两种情况分析:

1.确认应答ACK未能正确返回的情况
在这种情况下,数据是已经被对端主机成功接收了的,是不需要进行重新发送的。然而,如果在没有使用窗口控制的前提下,没有收到确认应答包的数据包都会被重发。但是,在使用了窗口控制以后,就如下图所示,某些应答包即使丢失了也无需重发,这也提高了传输效率。

在这里插入图片描述
如上图所示,一个段大小为1000字节,一个窗口大小为6000个字节的情况,主机A连续发送了6000序列号的数据,中间的主机B对1001的ACK丢失了,但是后面的2001的ACK正常返回了,说明前2000的序列号的数据都正常读取了,那么即使1001的ACK丢失也不需要进行数据重发!
所以在窗口控制的机制下,前面的ACK丢失,也能通过下一个ACK进行确认,提高了不少效率。
2.某个报文丢失的情况 如果当接收端主机接收到一个自己应该接收的序列号之外的数据包时,它会一直对当前接收到的数据包返回确认应答包。
在这里插入图片描述
如上图所示,主机A的1001-2000序列号的报文丢失了,它会一直收到来自主机B的一个1001的ACK,这个ACK就像在跟主机A提醒 “我想接收从1001开始的数据”。当主机A连续收到这个1001的确认应答ACK 3次后,就会认为数据丢失了,需要重发。
在滑动窗口比较大的情况下,同一个序列号的确认应答将会被重复不断地返回。而发送端主机如果 连续 3 次 接收到同一个确认应答包,就会将其对应的数据重发,这种机制比之前提到的“超时重发”更加高效,所以被称之为“高速重发控制”

拥塞控制与流量控制的区别

流量控制 是作用于接收者的,它是控制发送者的发送速度从而使接收者来得及接收,防止丢失数据包的。

拥塞控制 拥塞控制是作用于网络的,它是防止过多的数据注入到网络中,避免出现网络负载过大的情况

流量控制

所谓流量控制,就是让发送端不要发送的过快,让接收端能来得及接收

假设没有流量控制,发送端根据自己的实际情况发送数据,如果发送的速度太快,导致接收端的接收缓冲区很快填满了,此时发送端如果继续发送数据,接收端处理不过来,这时接收端就会把本来应该接收的数据丢弃,这会触发发送端的重发机制,从而导致网络流量的无端浪费。

所以TCP需要提供一种机制:让发送端根据接收端实际的接收能力控制发送的数据量。这就是所谓的流量控制。

TCP 利用滑动窗口实现流量控制的机制, 而滑动窗口大小是通过TCP首部的窗口大小字段来通知对方。

我们重温一下TCP的头部:
在这里插入图片描述
在TCP协议的头部信息当中,有一个16位字段的窗口大小,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大
不过,当接收端这个接收缓冲区面临数据溢出时,窗口大小的值就会随之设置成一个更小值,告诉发送端要控制一下发送的数据量了。
发送端接收到接收端的窗口变化指示后,就会对数据发送量进行调整,从而形成一个完整的流量控制。
流量控制的具体操作就是:接收端会在确认应答发送ACK报文时,将自己的即时窗口大小rwnd(receiver window)填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值进而改变自己的发送速度。

看看下面的图,展示了TCP流量控制的大概过程:
在这里插入图片描述
如上图所示,主机B接收到了一个1-1000序列号的数据包以后,返回一个ACK给发送端,并且告诉发送端它的窗口大小为3000,意味着发送端还能发送3000个字节的数据。
主机A收到指示后,继续发送数据,直到主机B收到3001-4000的数据段后其接收缓冲区满了,主机B的返回窗口大小为0,让主机A要暂停发数据了。

就是这样一个流程,可以防止发送端一次发送过大的数据导致接收端无法处理的情况。

那么另外一个问题来了:发送端停止发送数据后,什么时候可以继续发送数据呢?我们继续看上图,答案就是等接收端处理完了缓冲区的数据后发送一个窗口更新的数据包通知,发送端才可以继续根据窗口大小发送数据。但是如果发送端在重发超时的时间内都没有收到窗口更新的通知或者窗口更新的包丢失了,就没法正常通信了,那怎么办呢?

TCP为每一个连接设有一个持续计时器(persistence timer)。 只要TCP连接的一方收到对方的零窗口通知,就启动持续计时器。若持续计时器设置的时间到期,就发送一个零窗口控测数据段(这个数据段只包含一个字节),那么收到这个报文段的一方就重新设置持续计时器。

所以发送端会定时向接收端发送一个 窗口探测 的数据段,这目的是为了获取最新的窗口大小信息。

就这样,完成了TCP流量控制的整个过程。

拥塞控制

什么是拥塞
我们都知道计算机网络中的资源是有限的。某段时间内网络中对资源的需求超过了网络中的可用部分,而导致网络性能下降的情况就是拥塞。 通俗点说就是发送的数据包太多网络中的设备处理不过来,而导致网络性能下降的情况。

TCP 为什么要进行拥塞控制
网络中的路由器会有一个数据包处理队列,当路由器接收到的数据包太多而一下子处理不过来时,就会导致数据包处理队列过长。此时,路由器就会无条件的丢弃新接收到的数据封包。这就会导致上层的 TCP 协议以为数据包在网络中丢失,进而重传这些数据包,而路由器又会丢弃这些重传的数据包,如此以往,就会导致网络性能急剧下降,引起网络瘫痪。因此,TCP 需要控制数据包发送的数量来避免网络性能的下降。

拥塞控制原理
有了TCP的滑动窗口控制,收发主机之间即使不再以一个“段”为单位,而是以一个“窗口”为单位发送确认应答信号,所以发送主机够连续发送大量数据包。然而,如果在通信刚开始的时候就发送大量的数据包,也有可能会导致网络的瘫痪。

在拥塞控制中,发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。**拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。**发送窗口取拥塞窗口和接收端窗口的最小值,避免发送接收端窗口还大的数据。

拥塞控制使用了两个重要的算法: 慢启动算法, 拥塞避免算法

(一)慢启动算法:
慢启动算法的思路是,不要一开始就发送大量的数据,先试探一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。慢算法中,**每个传输轮次后将 cwnd 加倍。**举个例子:一开始发送方设置cwnd=1(为方便理解,这里用报文段的个数作为窗口大小的单位),然后每经过一个传输轮次,cwnd都发加倍,比如1, 2, 4, 8…指数增长。所以,这里的慢启动,不是指拥塞窗口增长慢,而是相对于一开始就上来传输大窗口的数据要显得慢。
在这里插入图片描述
当然,cwnd 的大小肯定不可能一直以这种指数的方式增长下去,要不然很快就会增长到引起网络崩溃的程度了。所以,经过一定时间或条件,我们就要换成拥塞避免算法来发送数据。
(二)拥塞避免算法:
拥塞避免算法也是逐渐的增大 cwnd 的大小,只是采用的是线性增长 而不是像慢启动算法那样的指数增长。具体来说就是每个传输轮次后将 cwnd 的大小加一(加法增大),如果发现出现网络拥塞的话就按照上面的方法重新设置ssthresh的大小(乘法减小,原来的二分之一)并从cwnd=1开始重新执行慢开始算法。

在这里插入图片描述
慢启动算法和拥塞避免算法结合:

问题:在拥塞控制中, 慢启动算法 和 拥塞避免算法 是怎么配合使用的呢?
像上面所说,慢启动算法下的cwnd大小是指数增长,所以不能任 cwnd 任意增长,所以我们引入一个慢启动门限(ssthresh)的阈值来控制 cwnd 的增长。
ssthresh的作用是:

  • 当cwnd < ssthresh时,使用慢开始算法。
  • 当cwnd > ssthresh时,改用拥塞避免算法。
  • 当cwnd = ssthresh时,慢开始与拥塞避免算法随机

还有一个问题就是这个 ssthresh 是怎么设置的呢? TCP/IP 中规定无论是在慢开始阶段还是在拥塞避免阶段,只要发现网络中出现拥塞(没有按时收到确认),就要把ssthresh设置为此时发送窗口的一半大小(不能小于2)。

在这里插入图片描述
如上图所示,拥塞控制的大致流程如下:

  • 一开始把ssthresh初始值设置成16,开始慢启动增加拥塞窗口cwnd,直到cwnd=16 停止慢启动,开始拥塞避免算法。
  • 使用拥塞避免算法线性增加cwnd,直到cwnd=24,这时候网络出现拥塞(ACK确认信号没有及时到达),把ssthresh设置成原来的一半,也就是ssthresh=12,同时把cwnd设为1。
  • 重新开始慢启动,直到cwnd到达ssthresh=12,然后执行拥塞避免算法进行加法增大,直到遇到网络拥塞,把ssthresh调成原来的一一半。
  • 如此反复动态计算cwnd,以达到拥塞控制的目的。

快重传 VS 超时重传

TCP 的可靠传输的原理就是超时重传机制,而重发机制有两种:超时重传机 和 快重传

TCP超时重传机制,结合上面说的慢启动拥塞避免使用就是发送完数据后开始倒计时,如果在重发超时内没有收到对接收方发来的ACK的话就去执行上述的乘法减小过程(设置sstresh为原来一半) 并重新开始慢开始算法,重新发送数据。

TCP快重传, 则是允许发送方再连续收到3 个重复的确认后就可以开始执行乘法减小过程而不必再等待重发超时时间。这就需要接收方每收到一个失序的报文段就立即发出重复确认以让发送发及早知道有报文段丢失,而不是等待自己发送数据的时候进行捎带确认。
TCP快重传的示意图如下:

在这里插入图片描述
如图,由于发送端不必等待每个数据段都确认才能继续发送,而是以一个窗口为单位发送数据,所以就算主机A发送的1001-2000序列号数据段丢失,主机A依然会继续发剩下的窗口大小数据,而此时主机B发现1001-2000数据丢失,它会每次收到其他序列号的数据包,都返回一个序列号2000的ACK,以此明确通知主机A,当主机A收到三次2000的ACK直到丢失了1001-2000数据包,就需要重传1001-2000的数据包了。
以此达到哪怕没到重发超时时间,都能快速重传的目的
快恢复
快恢复算法是与快重传算法配合使用的一个算法。
快恢复主要是指,当快重传的时候,发送方快速收到了3个重复的确认,因此会认为网络不是拥塞状态,所以在乘法减小过程(设置sstresh为原来一半),会启动 “拥塞避免”,而不是TCP超时重发机制的重新启动的慢启动

总结

TCP协议在实现传输可靠性上面做了很多:

  • 通过序列号和确认应答信号确保了数据不会重复发送和重复接收。
  • 同时通过超时重发控制保证即使数据包在传输过程中丢失,也能重发保持数据完整。
  • 通过三次握手,四次挥手建立和关闭连接的连接管理保证了端对端的通信可靠性。
  • TCP还使用了滑动窗口控制提高了数据传输效率
  • 过流量控制控制发送者的发送速度从而使接收者来得及接收,防止丢包。
  • 通过拥塞控制就是防止过多的数据注入到网络中,避免网络中的路由器或链路不致过载,导致数据丢失。从而保证了TCP传输的可靠性。

五.DNS/HTTP/HTTPS协议

DNS协议

如果说ARP协议是用来将IP地址转换为MAC地址,那么DNS协议则是用来将域名转换为IP地址(也可以将IP地址转换为相应的域名地址)。
我们都知道,TCP/IP中使用的是IP地址和端口号来确定网络上某一台主机上的某一个程序,不免有人有疑问,为什么不用域名来直接进行通信呢?

  1. 因为IP地址是固定长度的,IPv4是32位,IPv6是128位,而域名是变长的,不便于计算机处理。
  2. IP地址对于用户来说不方便记忆,但域名便于用户使用,例如www.baidu.com这是百度的域名。
    总结一点就是IP地址是面向主机的,而域名则是面向用户的。
    hosts文件
    域名和IP的对应关系保存在一个叫hosts文件中。
    最初,通过互联网信息中心来管理这个文件,如果有一个新的计算机想接入网络,或者某个计算IP变更都需要到信息中心申请变更hosts文件。其他计算机也需要定期更新,才能上网。
    但是这样太麻烦了,就出现了DNS系统。
    DNS系统
    一个组织的系统管理机构, 维护系统内的每个主机的IP和主机名的对应关系
    如果新计算机接入网络,将这个信息注册到数据库中
    用户输入域名的时候,会自动查询DNS服务器,由DNS服务器检索数据库,得到对应的IP地址
    我们可以通过命令查看自己的hosts文件:
    在域名解析的过程中仍然会优先查找hosts文件的内容
    在这里插入图片描述
    域名的分级
    域名可以划分为各个子域,子域还可以继续划分为子域的子域,这样就形成了顶级域、二级域、三级域等。
    如下图所示:
    在这里插入图片描述

其中顶级域名分为:国家顶级域名、通用顶级域名、反向域名。
域名解析过程
域名解析总体可分为一下过程:
(1) 输入域名后, 先查找自己主机对应的域名服务器,域名服务器先查找自己的数据库中的数据.
(2) 如果没有, 就向上级域名服务器进行查找, 依次类推
(3) 最多回溯到根域名服务器, 肯定能找到这个域名的IP地址
(4) 域名服务器自身也会进行一些缓存, 把曾经访问过的域名和对应的IP地址缓存起来, 可以加速查找过程
具体可描述如下:

  1. 主机先向本地域名服务器进行递归查询
  2. 本地域名服务器采用迭代查询,向一个根域名服务器进行查询
  3. 根域名服务器告诉本地域名服务器,下一次应该查询的顶级域名服务器的IP地址
  4. 本地域名服务器向顶级域名服务器进行查询
  5. 顶级域名服务器告诉本地域名服务器,下一步查询权限服务器的IP地址
  6. 本地域名服务器向权限服务器进行查询
  7. 权限服务器告诉本地域名服务器所查询的主机的IP地址
  8. 本地域名服务器最后把查询结果告诉主机
    如图所示:
    在这里插入图片描述

HTTP协议

HTTP协议的定义
超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。
什么是超文本
在互联网早期的时候,我们输入的信息只能保存在本地,无法和其他电脑进行交互。我们保存的信息通常都以文本即简单字符的形式存在,文本是一种能够被计算机解析的有意义的二进制数据包。而随着互联网的高速发展,两台电脑之间能够进行数据的传输后,人们不满足只能在两台电脑之间传输文字,还想要传输图片、音频、视频,甚至点击文字或图片能够进行超链接的跳转,那么文本的语义就被扩大了,这种语义扩大后的文本就被称为超文本(Hypertext)。
什么是传输
那么我们上面说到,两台计算机之间会形成互联关系进行通信,我们存储的超文本会被解析成为二进制数据包,由传输载体(例如同轴电缆,电话线,光缆)负责把二进制数据包由计算机终端传输到另一个终端的过程(对终端的详细解释可以参考 你说你懂互联网,那这些你知道么?这篇文章)称为传输(transfer)。
那么网络协议是什么呢?

网络协议就是网络中(包括互联网)传递、管理信息的一些规范。如同人与人之间相互交流是需要遵循一定的规矩一样,计算机之间的相互通信需要共同遵守一定的规则,这些规则就称为网络协议。

HTTP协议请求响应过程
当你在浏览器中输入网址后,到底发生了什么事情?你想要的内容是如何展现出来的?让我们通过一个例子来探讨一下,我们假设访问的 URL 地址为 http://www.someSchool.edu/someDepartment/home.index,当我们输入网址并点击回车时,浏览器内部会进行如下操作:
1.DNS服务器会首先进行域名的映射,找到访问www.someSchool.edu所在的地址,然后HTTP 客户端进程在 80 端口发起一个到服务器 www.someSchool.edu 的 TCP 连接(80 端口是 HTTP 的默认端口)。在客户和服务器进程中都会有一个套接字与其相连。
2.HTTP 客户端通过它的套接字向服务器发送一个 HTTP 请求报文。该报文中包含了路径 someDepartment/home.index 的资源,我们后面会详细讨论 HTTP 请求报文。
3.HTTP 服务器通过它的套接字接受该报文,进行请求的解析工作,并从其存储器(RAM 或磁盘)中检索出对象 www.someSchool.edu/someDepartment/home.index,然后把检索出来的对象进行封装,封装到 HTTP 响应报文中,并通过套接字向客户进行发送。
4.HTTP 服务器随即通知 TCP 断开 TCP 连接,实际上是需要等到客户接受完响应报文后才会断开 TCP 连接。
5.HTTP 客户端接受完响应报文后,TCP 连接会关闭。HTTP 客户端从响应中提取出报文中是一个 HTML 响应文件,并检查该 HTML 文件,然后循环检查报文中其他内部对象。
6.检查完成后,HTTP 客户端会把对应的资源通过显示器呈现给用户。

至此,键入网址再按下回车的全过程就结束了。上述过程描述的是一种简单的请求-响应全过程,真实的请求-响应情况可能要比上面描述的过程复杂很多。
浏览器向 DNS 服务器请求解析该 URL 中的域名所对应的 IP 地址;
解析出 IP 地址后,根据该 IP 地址和默认端口80,和服务器建立TCP连接;
浏览器发出读取文件(URL 中域名后面部分对应的文件)的HTTP 请求,该请求报文作为三次握手的第三个报文的数据发送给服务器;
服务器对浏览器请求作出响应,并把对应的 html 文本发送给浏览器;
释放 TCP连接;
浏览器将该 html 文本并显示内容;

HTTP报文格式
HTTP 协议主要由三大部分组成:
• 起始行(start line):描述请求或响应的基本信息;
• 头部字段(header):使用 key-value 形式更详细地说明报文;
• 消息正文(entity):实际传输的数据,它不一定是纯文本,可以是图片、视频等二进制数据。

其中起始行和头部字段并成为 请求头 或者 响应头,统称为 Header;消息正文也叫做实体,称为 body。HTTP 协议规定每次发送的报文必须要有 Header,但是可以没有 body,也就是说头信息是必须的,实体信息可以没有。而且在 header 和 body 之间必须要有一个空行(CRLF),如果用一幅图来表示一下的话,我觉得应该是下面这样
在这里插入图片描述
每个报文的起始行都是由三个字段组成:方法、URL 字段和 HTTP 版本字段
HTTP 请求方法
HTTP 请求方法一般分为 8 种,它们分别是
在这里插入图片描述

HTTP常见请求状态码和解释

首先出现的应该就是 200 OK,这是 HTTP 响应标头的状态码,它表示着响应成功完成。HTTP 响应标头的状态码有很多,并做了如下规定
以 2xx 为开头的都表示请求成功响应。
状态码 含义
200 成功响应
204 请求处理成功,但是没有资源可以返回
206 对资源某一部分进行响应,由Content-Range 指定范围的实体内容。
以 3xx 为开头的都表示需要进行附加操作以完成请求
状态码 含义
301 永久性重定向,该状态码表示请求的资源已经重新分配 URI,以后应该使用资源现有的 URI
302 临时性重定向。该状态码表示请求的资源已被分配了新的 URI,希望用户(本次)能使用新的 URI 访问。
303 该状态码表示由于请求对应的资源存在着另一个 URI,应使用 GET 方法定向获取请求的资源。
304 该状态码表示客户端发送附带条件的请求时,服务器端允许请求访问资源,但未满足条件的情况。
307 临时重定向。该状态码与 302 Found 有着相同的含义。
以 4xx 的响应结果表明客户端是发生错误的原因所在。
状态码 含义
400 该状态码表示请求报文中存在语法错误。当错误发生时,需修改请求的内容后再次发送请求。
401 该状态码表示发送的请求需要有通过 HTTP 认证(BASIC 认证、DIGEST 认证)的认证信息。
403 该状态码表明对请求资源的访问被服务器拒绝了。
404 该状态码表明服务器上无法找到请求的资源。
以 5xx 为开头的响应标头都表示服务器本身发生错误
状态码 含义
500 该状态码表明服务器端在执行请求时发生了错误。
503 该状态码表明服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

HTTP发展历史

HTTP1.0和HTTP1.1的一些区别

  1. 缓存处理,在HTTP1.0中主要使用header里的If-Modified-Since,Expires来做为缓存判断的标准,HTTP1.1则引入了更多的缓存控制策略例如Entity tag,If-Unmodified-Since, If-Match, If-None-Match等更多可供选择的缓存头来控制缓存策略。
  2. 带宽优化及网络连接的使用,HTTP1.0中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,HTTP1.1则在请求头引入了range头域,它允许只请求资源的某个部分,即返回码是206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。 错误通知的管理,在HTTP1.1中新增了24个错误状态响应码,如409(Conflict)表示请求的资源与资源的当前状态发生冲突;410(Gone)表示服务器上的某个资源被永久性的删除。
  3. Host头处理,在HTTP1.0中认为每台服务器都绑定一个唯一的IP地址,因此,请求消息中的URL并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机(Multi-homed Web Servers),并且它们共享一个IP地址。HTTP1.1的请求消息和响应消息都应支持Host头域,且请求消息中如果没有Host头域会报告一个错误(400 Bad Request)。
  4. 长连接,HTTP 1.1支持长连接(PersistentConnection)和请求的流水线(Pipelining)处理,在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟,在HTTP1.1中默认开启Connection: keep-alive,一定程度上弥补了HTTP1.0每次请求都要创建连接的缺点。
    HTTP2.0的新特性
  5. 新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。
  6. 多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。
  7. header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。
  8. 服务端推送(server push),HTTP2.0具有server push功能。

HTTPS协议

背景:
• Htttp采用明文传输信息,存在信息窃听,信息篡改的风险,而协议TLS/SSL具有身份验证、信息加密和完整性校验的功能,可以完全避免此类问题发生。
• 窃听相同段上的通信很简单,只需要收集在互联网上流动的数据包就可以,对于收集这些数据包的工作交给抓包工具就可以实现了。
• TSL/SSL全称安全传输协议,是介于TCP和HTTP之间的一层安全协议,不影响原有的TCP协议和HTTP协议,所以使用HTTPS基本不需要对HTTP页面进行太多的改造。
• HTTPS = HTTP+ TLS/SSL
在这里插入图片描述
• TSL/SSL主要依赖三类基本算法:散列函数Hash、对称加密和非对称加密,其利用非对称加密实现身份认证和密钥协商,对称加密算法采用协商的密钥对数据加密,基于散列函数验证信息的完整性。!
在这里插入图片描述
https过程

  • 客户端使用HTTPS的URL访问Web服务器,要求与WEb服务器建立SSL连接
  • Web服务器收到客户端的请求后,会将网站信息(证书中包含公钥)传送一份给客户端
  • 客户端的浏览器与Web服务器协商SSL/TSL连接的安全协议等级,也就是信息加密的等级
  • 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将对话的密钥加密并·传送网站
  • Web服务器利用自己的私钥密出会话密钥
  • web服务器利用会话密钥加密与客户端之间进行通信

https的优点

  • 客户端产生的密钥只有客户端和服务器端能得到

  • 加密的数据只有客户端和服务端才能得到明文

  • 客户端到服务端的通信是安全的

https的局限/缺点

  • HTTPS比HTTP耗费更多的服务器资源(https其实就是构建在SSL/TSL上的http协议,所以https比http多用多少服务器资源,主要看SSL/TSL本身消耗多少服务器资源)

  • HTTPS并不能防止站点被网络蜘蛛抓取。某些情形下被加密资源的URL可仅通过截获请求和响应大小推得,这就可使攻击者同时知道明文(公开的静态内容)和密文(被加密过的明文),从而选择密文攻击成为可能

  • SSL证书需要绑定IP,不能在同一IP上绑定多个域名、

HTTPS缺点
HTTPS的缺点是使用了SSL,速度会变慢,HTTPS比HTTP慢2到100倍

  1. SSL有两种慢
  2. 通信慢
  3. 大量消耗CPU和内存资源,导致处理速度变慢
  4. 购买证书需要成本
  5. 正因为HTTPS影响性能
  6. 所以WEB服务中只对敏感信息才使用HTTPS加密,非敏感信息仍然使用HTTP通信

为什么https安全;
它使用了SSL/TLS协议传输,包含证书、卸载、流量转发、负载均衡、页面适配等,保障了传输的安全性
HTTP 的优点
简单灵活易扩展
HTTP 最重要也是最突出的优点是 简单、灵活、易于扩展。
HTTP 的协议比较简单,它的主要组成就是 header + body,头部信息也是简单的文本格式,而且 HTTP 的请求报文根据英文也能猜出来个大概的意思,降低学习门槛,能够让更多的人研究和开发 HTTP 应用。
所以,在简单的基础上,HTTP 协议又多了灵活 和 易扩展 的优点。
HTTP 协议里的请求方法、URI、状态码、原因短语、头字段等每一个核心组成要素都没有被制定死,允许开发者任意定制、扩充或解释,给予了浏览器和服务器最大程度的信任和自由。
应用广泛、环境成熟
因为过于简单,普及,因此应用很广泛。因为 HTTP 协议本身不属于一种语言,它并不限定某种编程语言或者操作系统,所以天然具有跨语言、跨平台的优越性。而且,因为本身的简单特性很容易实现,所以几乎所有的编程语言都有 HTTP 调用库和外围的开发测试工具。
随着移动互联网的发展, HTTP 的触角已经延伸到了世界的每一个角落,从简单的 Web 页面到复杂的 JSON、XML 数据,从台式机上的浏览器到手机上的各种 APP、新闻、论坛、购物、手机游戏,你很难找到一个没有使用 HTTP 的地方。
无状态
无状态其实既是优点又是缺点。因为服务器没有记忆能力,所以就不需要额外的资源来记录状态信息,不仅实现上会简单一些,而且还能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。

HTTP缺点
1.使用明文进行传输,内容可能被窃听
TCP/IP协议族的工作机制,通信内容在所有的通信线路上都可能遭到窥视
2.不验证通信方的身份,通信方的身份可能是伪装
在http协议中的请求和响应不会对通信方进行确认,任何人都可以发起请求,另外服务器只需要接受到请求,不管对方是谁都会返回一个响应。(对方的IP和端口没有被WEB服务器设定限制访问的情况下)
HTTP常见隐患:
1.可能将响应信息发送到伪装客户端上
2.有可能请求到伪装的服务器
3.无法确定对方是否具有访问权限
4.即使是无意义的请求也照单全收,无法阻止海量请求下的DOS攻击
5.无法证明报文的完整性,报文可能被篡改

HTTP本身不具有保存之前发送请求和响应的功能,使用HTTP协议,每当有新的请求发生,就会有对应的新响应产生,协议不保存请求或响应报文的信息,这是为了更快的处理业务,确保协议的可伸缩性,而特意把HTTP设置的如此简单。

六.Cookie和Session

为什么需要cookie和session

在Web发展史中,我们知道浏览器与服务器间采用的是 http协议,而这种协议是无状态的,所以这就导致了服务器无法知道是谁在浏览网页,但很明显,一些网页需要知道用户的状态,例如登陆,购物车等。
所以为了解决这一问题,先后出现了四种技术,分别是隐藏表单域,URL重写,cookie,session,而用的最多也是比较重要的就是cookie和session了。

Cookie

是什么
cookie是浏览器保存在用户电脑上的一小段文本,通俗的来讲就是当一个用户通过 http访问到服务器时,服务器会将一些 Key/Value键值对返回给客户端浏览器,并给这些数据加上一些限制条件,在条件符合时这个用户下次访问这个服务器时,数据通过请求头又被完整地给带回服务器,服务器根据这些信息来判断不同的用户。
也就是说, cookie是服务器传给客户端并保存在客户端的一段信息,这个 Cookie是有大小,数量限制的!!
Cookie的创建
当前 Cookie有两个版本,分别对应两种设置响应头:“Set-Cookie”和 “Set-Cookie2”。在Servlet中并不支持Set-Cookie2,所以我们来看看Set-Cookie的属性项:
在这里插入图片描述
这些属性项,其他的都说的很清楚了,我们来看看Domain有什么用:
现在,我们假设这里有两个域名:
域名A:a.b.f.com.cn 域名B:c.d.f.com.cn
显然,域名A和域名B都是 f.com.cn的子域名

  • 如果我们在域名A中的Cookie的domain设置为f.com.cn,那么f.com.cn及其子域名都可以获取这个Cookie,即域名A和域名B都可以获取这个Cookie
  • 如果域名A和域名B同时设置Cookie的doamin为f.com.cn,那么将出现覆盖的现象
  • 如果域名A没有显式设置Cookie的domain方法,那么domain就为a.b.f.com.cn,不一样的是,这时,域名A的子域名将无法获取这个Cookie

好的,现在了解完了Set-Cookie的属性项,开始创建Cookie
Web服务器通过发送一个称为Set-Cookie的http消息来创建一个Cookie:
Set-Cookie: value[; expires=date][; domain=domain][; path=path][; secure]
这里我们思考一个问题,当我们在服务器创建多个Cookie时,这些Cookie最终是在一个Header项中还是以独立的Header存在的呢?
在这里插入图片描述
我们可以看到,构建http返回字节流时是将Header中所有的项顺序写出,而没有进行任何修改。所以可以想象在浏览器在接收http返回的数据时是分别解析每一个Header项。
接着,在客户端进行保存,如何保存呢?这里又要对Cookie进行进一步的了解
Cookie的分类

  • 会话级别Cookie:所谓会话级别Cookie,就是在浏览器关闭之后Cookie就会失效。
  • 持久级别Cookie:保存在硬盘的Cookie,只要设置了过期时间就是硬盘级别Cookie。

好的,现在cookie保存在了客户端,当我们去请求一个URL时,浏览器会根据这个URL路径将符合条件的Cookie放在请求头中传给服务器。

Session

Cookie是有大小限制和数量限制的,并且越来越多的Cookie代表客户端和服务器的传输量增加,可不可以每次传的时候不传所有cookie值,而只传一个唯一ID,通过这个ID直接在服务器查找用户信息呢?答案是有的,这就是我们的session。
Session是基于Cookie来工作的,同一个客户端每次访问服务器时,只要当浏览器在第一次访问服务器时,服务器设置一个id并保存一些信息(例如登陆就保存用户信息,视具体情况),并把这个id通过Cookie存到客户端,客户端每次和服务器交互时只传这个id,就可以实现维持浏览器和服务器的状态,而这个ID通常是NAME为JSESSIONID的一个Cookie。
实际上,有四种方式让Session正常工作:

  • 通过URL传递SessionID
  • 通过Cookie传递SessionID
  • 通过SSL传递SessionID
  • 通过隐藏表单传递SessionID

第一种情况:
当浏览器不支持Cookie功能时,浏览器会将用户的SessionCookieName(默认为JSESSIONID)重写到用户请求的URL参数中。格式:/path/Servlet;name=value;name2=value2?Name3=value3
第三种情况:
会根据javax.servlet.request.ssl_session属性值设置SessionID。
注:如果客户端支持Cookie,又通过URL重写,Tomcat仍然会解析Cookie中的SessionID并覆盖URL中的SessionID。

二者的异同
相同点(有关系的地方):

  • Session和Cookie都是为了让http协议又状态而存在
  • Session通过Cookie工作,Cookie传输的SessionID让Session知道这个客户端到底是谁

不同点:

  • Session将信息保存到服务器,Cookie将信息保存在客户端

工作流程
当浏览器第一次访问服务器时,服务器创建Session并将SessionID通过Cookie带给浏览器保存在客户端,同时服务器根据业务逻辑保存相应的客户端信息保存在session中;客户端再访问时上传Cookie,服务器得到Cookie后获取里面的SessionID,来维持状态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值