网络
Table of Contents generated with DocToc (opens new window)
- 思维导图
- 重点
- 1.TCP三次握手
- 2.TCP四次挥手
- 3.TCP和UDP是什么
- 4.TCP和UDP有什么区别
- 5.TCP维护可靠的通信方式
- 6.TCP/IP的流量控制
- 7.拥塞控制
- 8.ARP是地址解析协议,简单解释下工作原理
- 9.ICMP协议
- 10.DHCP协议
- 11.TTL是什么?作用是什么?哪些工具会用到它?
- 12.web页面的请求过程
- 13.DNS(Domain Name System)
# 思维导图
# 重点
- TCP/IP协议体系的认知
- 链路层
- 以太网帧的格式
- MTU的概念
- ARP协议和RARP协议(掌握一下ARP缓存的原理)
- 网络层
- 掌握IP的首部格式
- 掌握IP的分片
- 掌握IP选路
- ICMP协议
- 掌握报文格式
- 分类:查询 + 差错
- 两种 + 五种
- 传输层
- UDP,次要一点,掌握特点和首部各个字段
- 掌握TCP
- 特点 + 首部字段 + 可靠机制
- 连接控制 : 三次握手,四次挥手,同时打开,同时关闭,半关闭(可能问到为什么需要)
- 流量控制机制:滑动窗口,慢启动,拥塞避免,快速重传,快速恢复
- 超时重传机制:各种定时器
- 应用层
- 掌握DNS协议
- 名字空间
- 指针查询(反向查找或逆向解析)基本原理
- DNS缓存
- FTP协议(活化石):
- 控制流和数据流
- 两种工作模式: PASV 和 PORT
- 各种指令和响应码
- 断点续传和匿名FTP的概念
- HTTP协议:
- 报文格式:请求报文,响应报文,请求头各种字段,响应头各种字段
- HTTP状态码
- HTTPS协议
- 握手的详细过程
- 摘要算法,数字签名,数字证书的原理和过程
- 掌握DNS协议
# 1.TCP三次握手
三次握手(Three-way Handshake)其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。
刚开始客户端处于 Closed 的状态,服务端处于 Listen 状态。 进行三次握手:
第一次握手:(
客户端给服务器发送TCP连接请求
)客户端给服务端发一个 SYN 报文,并指明客户端的初始化序列号 ISN。此时客户端处于 SYN_SENT 状态。首部的同步位SYN=1,初始序号seq=x,
TCP的标准规定,SYN=1的报文段不能携带数据,但要消耗掉一个序号
。第二次握手:(
服务器给客户端发送针对TCP连接请求的确认
)服务器收到客户端的 SYN 报文之后,会以自己的 SYN 报文作为应答,并且也是指定了自己的初始化序列号 ISN(s)。同时会把客户端的 ISN + 1 作为ACK 的值,表示自己已经收到了客户端的 SYN,此时服务器处于SYN_RCVD
的状态。在确认报文段中SYN=1,ACK=1,确认号ack=x+1,初始序号seq=y。
第三次握手:(
客户端给服务器发送针对TCP连接请求的确认的确认
)客户端收到 SYN 报文之后,会发送一个 ACK 报文,当然,也是一样把服务器的 ISN + 1 作为 ACK 的值,表示已经收到了服务端的 SYN 报文,此时客户端处于ESTABLISHED
状态。服务器收到 ACK 报文之后,也处于ESTABLISHED
状态,此时,双方已建立起了连接。确认报文段ACK=1,确认号ack=y+1,序号seq=x+1(初始为seq=x,第二个报文段所以要+1),ACK报文段可以携带数据,不携带数据则不消耗序号。
TCP的标准规定,普通的确认报文,如果不携带数据,则不消耗序号
发送第一个SYN的一端将执行主动打开(active open),接收这个SYN并发回下一个SYN的另一端执行被动打开(passive open)。
在socket编程中,客户端执行connect()时,将触发三次握手。
下图中服务器发送给客户端的确认报文中,服务端的初始序号seq=y,可由服务端随机指定,与其他报文段中的值无关
# 1.1为什么需要三次握手,两次不行吗?
弄清这个问题,我们需要先弄明白三次握手的目的是什么,能不能只用两次握手来达到同样的目的。
第一次握手:客户端发送网络包,服务端收到了。 这样服务端就能得出结论:客户端的发送能力、服务端的接收能力是正常的。
第二次握手:服务端发包,客户端收到了。 这样客户端就能得出结论:服务端的接收、发送能力,客户端的接收、发送能力是正常的。不过此时服务器并不能确认客户端的接收能力是否正常。
第三次握手:客户端发包,服务端收到了。 这样服务端就能得出结论:客户端的接收、发送能力正常,服务器自己的发送、接收能力也正常。
因此,需要三次握手才能确认双方的接收与发送能力是否正常。
试想如果是用两次握手,则会出现下面这种情况:
如客户端发出连接请求,但因连接请求报文丢失而未收到确认,于是客户端再重传一次连接请求。后来收到了确认,建立了连接。数据传输完毕后,就释放了连接,客户端共发出了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,但是第一个丢失的报文段只是在
某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端
,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,同意建立连接,不采用三次握手,只要服务端发出确认,就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
所以不采用两次握手是为了防止已失效的连接请求报文段突然又传送到了TCP服务器,因而导致服务器长时间等待,浪费资源
# 1.2 什么是半连接队列?
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列
里,我们把这种队列称之为半连接队列
。
当然还有一个全连接队列
,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
这里在补充一点关于SYN-ACK 重传次数
的问题:
服务器发送完SYN-ACK包,如果未收到客户确认包,服务器进行首次重传,等待一段时间仍未收到客户确认包,进行第二次重传。如果重传次数超过系统规定的最大重传次数,系统将该连接信息从半连接队列中删除。
注意,每次重传等待的时间不一定相同,一般会是指数增长,例如间隔时间为 1s,2s,4s,8s…
# 1.3 ISN(Initial Sequence Number)是固定的吗?
当一端为建立连接而发送它的SYN时,它为连接选择一个初始序号。ISN随时间而变化,因此每个连接都将具有不同的ISN。ISN可以看作是一个32比特的计数器,每4ms加1 。这样选择序号的目的在于防止在网络中被延迟的分组在以后又被传送,而导致某个连接的一方对它做错误的解释。
三次握手的其中一个重要功能是客户端和服务端交换 ISN(Initial Sequence Number),以便让对方知道接下来接收数据的时候如何按序列号组装数据。如果 ISN 是固定的,攻击者很容易猜出后续的确认号,因此 ISN 是动态生成的。
# 1.4 三次握手过程中可以携带数据吗?
其实第三次握手的时候,是可以携带数据的。但是,第一次、第二次握手不可以携带数据
为什么这样呢?大家可以想一个问题,假如第一次握手可以携带数据的话,如果有人要恶意攻击服务器,那他每次都在第一次握手中的 SYN 报文中放入大量的数据。因为攻击者根本就不理服务器的接收、发送能力是否正常,然后疯狂着重复发 SYN 报文的话,这会让服务器花费很多时间、内存空间来接收这些报文。
也就是说,第一次握手不可以放数据,其中一个简单的原因就是会让服务器更加容易受到攻击了。而对于第三次的话,此时客户端已经处于 ESTABLISHED 状态。对于客户端来说,他已经建立起连接了,并且也已经知道服务器的接收、发送能力是正常的了,所以能携带数据也没啥毛病。
# 1.5 SYN攻击是什么?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击。SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复确认包,并等待Client确认,由于源地址不存在,因此Server需要不断重发直至超时,这些伪造的SYN包将长时间占用未连接队列,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。SYN 攻击是一种典型的 DoS/DDoS 攻击。
检测 SYN 攻击非常的方便,当你在服务器上看到大量的半连接状态时,特别是源IP地址是随机的,基本上可以断定这是一次SYN攻击。在 Linux/Unix 上可以使用系统自带的 netstat 命令来检测 SYN 攻击。
netstat -n -p TCP | grep SYN_RECV
常见的防御 SYN 攻击的方法有如下几种:
- 缩短超时(SYN Timeout)时间
- 增加最大半连接数
- 过滤网关防护
- SYN cookies技术
# 2.TCP四次挥手
建立一个连接需要三次握手,而终止一个连接要经过四次挥手(也有将四次挥手叫做四次握手的)。这由TCP的半关闭(half-close)造成的。所谓的半关闭,其实就是TCP提供了连接的一端在结束它的发送后还能接收来自另一端数据的能力。
TCP 连接的拆除需要发送四个包,因此称为四次挥手(Four-way handshake),客户端或服务端均可主动发起挥手动作。
刚开始双方都处于ESTABLISHED
状态,假如是客户端先发起关闭请求。四次挥手的过程如下:
第一次挥手:客户端发送一个 FIN 报文,报文中会指定一个序列号。此时客户端处于 FIN_WAIT1 状态。 即发出
连接释放报文段
(FIN=1,序号seq=u),并停止再发送数据,主动关闭TCP连接,进入FIN_WAIT1
(终止等待1)状态,等待服务端的确认。序号seq=u中的u等于TCP客户进程之前传送过的数据的最后一个字节+1
TCP规定,终止位FIN等于1的报文段即使不携带数据,也要消耗掉一个序号
ack字段的值v等于客户进程之前已收到的数据的最后一个字节的序号+1
(等于服务器进程传送过的数据的最后一个字节)第二次挥手:服务端收到 FIN 之后,会发送 ACK 报文,且把客户端的序列号值 +1 作为 ACK 报文的序列号值,表明已经收到客户端的报文了,此时服务端处于
CLOSE_WAIT
状态。 即服务端收到连接释放报文段后即发出确认报文段
(ACK=1,确认号ack=u+1,序号seq=v),服务端进入CLOSE_WAIT
(关闭等待)状态,此时的TCP处于半关闭状态,客户端到服务端的连接释放。客户端收到服务端的确认后,进入FIN_WAIT2
(终止等待2)状态,等待服务端发出的连接释放报文段。seq=v中的v等于TCP服务器进程之前已传送过的数据的最后一个字节的序号+1
ack=u+1中的u等于TCP服务器进程之前已收到的数据的最后一个字节的序号+1
第三次挥手:如果服务端也想断开连接了,和客户端的第一次挥手一样,发给 FIN 报文,且指定一个序列号。此时服务端处于
LAST_ACK
的状态。 即服务端没有要向客户端发出的数据,服务端发出连接释放报文段
(FIN=1,ACK=1,序号seq=w,确认号ack=u+1),服务端进入LAST_ACK
(最后确认)状态,等待客户端的确认。第四次挥手:客户端收到 FIN 之后,一样发送一个 ACK 报文作为应答,且把服务端的序列号值 +1 作为自己 ACK 报文的序列号值,此时客户端处于
TIME_WAIT
状态。需要过一阵子以确保服务端收到自己的 ACK 报文之后才会进入CLOSED
状态,服务端收到 ACK 报文之后,就处于关闭连接了,处于CLOSED
状态。 即客户端收到服务端的连接释放报文段后,对此发出确认报文段
(ACK=1,seq=u+1,ack=w+1),客户端进入TIME_WAIT
(时间等待)状态。此时TCP未释放掉,需要经过时间等待计时器设置的时间2MSL后,客户端才进入CLOSED
状态。
收到一个FIN只意味着在这一方向上没有数据流动。客户端执行主动关闭并进入TIME_WAIT是正常的,服务端通常执行被动关闭,不会进入TIME_WAIT状态。
在socket编程中,任何一方执行close()操作即可产生挥手操作。
# 2.1 挥手为什么需要四次?
因为当服务端收到客户端的SYN连接请求报文后,可以直接发送SYN+ACK报文。其中ACK报文是用来应答的,SYN报文是用来同步的。但是关闭连接时,当服务端收到FIN报文时,很可能并不会立即关闭SOCKET,所以只能先回复一个ACK报文,告诉客户端,“你发的FIN报文我收到了”。只有等到我服务端所有的报文都发送完了,我才能发送FIN报文,因此不能一起发送。故需要四次挥手。
# 2.2 2MSL等待状态
如果客户端不等待,而是直接关闭,会导致以下情况
MSL是Maximum Segment Lifetime的英文缩写,可译为“最长报文段寿命”,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。
TIME_WAIT状态也成为2MSL等待状态。每个具体TCP实现必须选择一个报文段最大生存时间MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间。这个时间是有限的,因为TCP报文段以IP数据报在网络内传输,而IP数据报则有限制其生存时间的TTL字段。
对一个具体实现所给定的MSL值,处理的原则是:当TCP执行一个主动关闭,并发回最后一个ACK,该连接必须在TIME_WAIT状态停留的时间为2倍的MSL。这样可让TCP再次发送最后的ACK以防这个ACK丢失(另一端超时并重发最后的FIN)。
这种2MSL等待的另一个结果是这个TCP连接在2MSL等待期间,定义这个连接的插口(客户的IP地址和端口号,服务器的IP地址和端口号)不能再被使用。这个连接只能在2MSL结束后才能再被使用。
# 2.3 四次挥手释放连接时,等待2MSL的意义?
为了保证客户端发送的最后一个ACK报文段能够到达服务器。因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。
# 两个理由:
保证客户端发送的最后一个ACK报文段能够到达服务端。
这个ACK报文段有可能丢失,使得处于LAST-ACK状态的B收不到对已发送的FIN+ACK报文段的确认,服务端超时重传FIN+ACK报文段,而客户端能在2MSL时间内收到这个重传的FIN+ACK报文段,接着客户端重传一次确认,重新启动2MSL计时器,最后客户端和服务端都进入到CLOSED状态,若客户端在TIME-WAIT状态不等待一段时间,而是发送完ACK报文段后立即释放连接,则无法收到服务端重传的FIN+ACK报文段,所以不会再发送一次确认报文段,则服务端无法正常进入到CLOSED状态。
防止“已失效的连接请求报文段”出现在本连接中。
客户端在发送完最后一个ACK报文段后,再经过2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失,使下一个新的连接中不会出现这种旧的连接请求报文段。
# 2.4 服务器端的保活计时器
# 2.5 为什么TIME_WAIT状态需要经过2MSL才能返回到CLOSE状态?
理论上,四个报文都发送完毕,就可以直接进入CLOSE状态了,但是可能网络是不可靠的,有可能最后一个ACK丢失。所以TIME_WAIT状态就是用来重发可能丢失的ACK报文。
# 2.6 TCP状态变迁图
# 2.7 TCP报文段的首部格式
- 为了实现可靠传输,TCP采用了面向字节流的方式
- 但TCP在发送数据时,是从发送缓存取出一部分或全部字节并给其添加一个首部使之成为TCP报文段后进行发送
- 一个TCP报文段由
首部
和数据载荷
两部分构成 - TCP的全部功能都体现在它首部中各字段的作用
- 一个TCP报文段由
首部格式:
保留:占6比特,保留为今后使用,但目前应置为零
-
应从接收窗口和拥塞窗口中取小者
校验和(不重要):占16比特,用来检查整个TCP报文段在传输过程中是否出现了误码,检查范围包括TCP报文段的首部和数据载荷两部分。在计算校验和时,要在TCP报文段的前面加上12字节的伪首部。
-
接收方收到紧急标志为1的报文段,会按照紧急指针字段的值,从报文段数据载荷部分取出紧急数据,并直接上交给应用进程,而不必在接收缓存中排队
# 3.TCP和UDP是什么
TCP: 传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 定义。
UDP: Internet 协议集支持一个无连接的传输协议,该协议称为用户数据报协议(UDP,User Datagram Protocol)。UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据包的方法。RFC 768 描述了 UDP。
# 4.TCP和UDP有什么区别
TCP面向连接,通过三次握手建立连接,四次挥手接除连接
;UDP是无连接的,即发送数据之前不需要建立连接
,这种方式为UDP带来了高效的传输效率,但也导致无法确保数据的发送成功。TCP是可靠的通信方式
。通过TCP连接传送的数据,TCP通过超时重传、 数据校验等方式来确保数据无差错,不丢失,不重复,且按序到达;而UDP由于无需连接的原因,将会以最大速度进行传输,但不保证可靠交付,也就是会出现丢失、重复等等问题
。TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流
,由于连接的问题,当网络出现波动时,连接可能出现响应问题;UDP对应用进程交下来的报文既不合并也不拆分,即UDP是面向应用报文的
,UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低。每一条TCP连接只能是点到点的
;而UDP不建立连接,所以可以支持一对一,一对多,多对一和多对多
的交互通信,也就是可以同时接受多个人的包。TCP需要建立连接,
首部开销
20字节相比8个字节的UDP显得比较大。TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道。
# 5.TCP维护可靠的通信方式
- 数据分片:在发送端对用户数据进行分片,在接收端进行重组,由TCP确定分片的大小并控制分片和重组;
- 到达确认:接收端接收到分片数据时,根据分片数据序号向发送端发送一个确认包;
- 超时重发:发送方在发送分片后计时,若超时却没有收到相应的确认包,将会重发对应的分片;
- 滑动窗口:TCP连接双方的接收缓冲空间大小都固定,接收端只能接受缓冲区能接纳的数据。
- 失序处理:TCP的接收端需要重新排序接收到的数据。
- 重复处理:如果传输的TCP分片出现重复,TCP的接收端需要丢弃重复的数据。
- 数据校验:TCP通过保持它首部和数据的检验和来检测数据在传输过程中的任何变化。
# 6.TCP/IP的流量控制
需要流量控制的原因
数据发送的过快接受放来不及接受会造成数据丢失
如何控制
让发送方的发生速率不要太快,接收方来得及接受
具体:利用滑动窗口机制
- 由接收方控制流量,收到的数据会发送确认,确认之后发送方的窗口会向前滑动发送接下来的字节
- 当接收方没有内存会告诉发送方能接受的字节为0 ,但是这个消息可能会丢失,丢失之后发送方和接收方都会一直等待对方发送数据,会形成死锁
- 首先如果接收方收到0字节通知会启动一个持续计时器,计时器超时的话会发送一个0窗口探测报文,发送方收到就会返回自己现在能接受的数据大小,死锁解除,如果还是0就再开启一个计时器
- 如果零窗口探测报文丢失的话,也有一个计时器,这个计时器超时探测报文也会重传
# 6.1 滑动窗口机制
滑动窗口通俗来讲就是一种流量控制技术
它本质上是描述接收方的TCP数据报缓冲区大小的数据,发送方根据这个数据来计算自己最多能发送多长的数据,如果发送方收到接收方的窗口大小为0的TCP数据报,那么发送方将停止发送数据,等到接收方发送窗口大小不为0的数据报的到来
所谓滑动窗口协议,自己理解有两点:1. “窗口”对应的是一段可以被发送者发送的字节序列,其连续的范围称之为“窗口”;2. “滑动”则是指这段“允许发送的范围”是可以随着发送的过程而变化的,方式就是按顺序“滑动”。在引入一个例子来说这个协议之前,我觉得很有必要先了解以下前提:
- TCP协议的两端分别为发送者A和接收者B,由于是全双工协议,因此A和B应该分别维护着一个独立的发送缓冲区和接收缓冲区,由于对等性(A发B收和B发A收),我们以A发送B接收的情况作为例子;
- 发送窗口是发送缓存中的一部分,是可以被TCP协议发送的那部分,其实应用层需要发送的所有数据都被放进了发送者的发送缓冲区;
- 发送窗口中相关的有四个概念:已发送并收到确认的数据(不再发送窗口和发送缓冲区之内)、已发送但未收到确认的数据(位于发送窗口之中)、允许发送但尚未发送的数据以及发送窗口外发送缓冲区内暂时不允许发送的数据;
- 每次成功发送数据之后,发送窗口就会在发送缓冲区中按顺序移动,将新的数据包含到窗口中准备发送;
# 过程举例
# 为什么接收窗口大小为0,还能接收零窗口探测报文段?
TCP规定,即使接收窗口大小为0,也必须接收零窗口探测报文段、确认报文段、携带有紧急数据的报文段
零窗口探测报文也有重传计时器,重传计时器超时,零窗口探测报文会重传,所以不用担心零窗口探测报文的丢失
TCP建立连接的初始,B会告诉A自己的接收窗口大小,比如为‘20’: 字节31-50为发送窗口
A发送11个字节后,发送窗口位置不变,B接收到了乱序的数据分组:
只有当A成功发送了数据,即发送的数据得到了B的确认之后,才会移动滑动窗口离开已发送的数据;同时B则确认连续的数据分组,对于乱序的分组则先接收下来,避免网络重复传递:
如果出现丢包现象:(如图中的7、8、9丢失)
B给A发确认号为7,确认数据包中有“选择性确认段”,此时A只发送丢失的7-9,而不会再发10-12。
# 6.2 传递效率
一个显而易见的问题是:单个发送字节单个确认,和窗口有一个空余即通知发送方发送一个字节,无疑增加了网络中的许多不必要的报文(请想想为了一个字节数据而添加的40字节头部吧!),所以我们的原则是尽可能一次多发送几个字节,或者窗口空余较多的时候通知发送方一次发送多个字节。对于前者我们广泛使用Nagle算法,即:
- 若发送应用进程要把发送的数据逐个字节地送到TCP的发送缓存,则发送方就把第一个数据字节先发送出去,把后面的字节先缓存起来;
- 当发送方收到第一个字节的确认后(也得到了网络情况和对方的接收窗口大小),再把缓冲区的剩余字节组成合适大小的报文发送出去;
- 当到达的数据已达到发送窗口大小的一半或以达到报文段的最大长度时,就立即发送一个报文段;对于后者我们往往的做法是让接收方等待一段时间,或者接收方获得足够的空间容纳一个报文段或者等到接受缓存有一半空闲的时候,再通知发送方发送数据。
# 7.拥塞控制
# 7.1 什么是拥塞?什么是拥塞控制?
在某段时间内,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就称为拥塞。简单的说拥塞产生的原因有两点:(1)接收方容量不够(2)网络内部有瓶颈
拥塞控制就是防止过多的数据注入到网络中,这样可以使网络中的
路由器或链路
不致过载。
# 7.2 检测网络拥塞的方法?
发送数据后规定时间没有收到回应可以判定堵塞
发送数据后收到同一条报文的四次确认,可认为丢失-------------这种情况就是根据TCP传输数据的特点:发送12345个数据段,接受端收到1的时候会返回2的确认报文也就是说我收到了2之前的下一次我就想要2了--------收到2之后返回3的确认报文------但是现在3迟迟未到-------4到了储存下来还是返回3的确认---5到了还是如此----然后3才到又发现缓存里面有45就返回6的确认报文表示之前的我都收到了,
若发送方接收到对同一条报文的三次冗余确认(也就是四次确认),就认为这条报文的下一条已经丢失,于是不管计时器是否超时,都直接重传这条报文的下一条。快速重传的条件发生,发送方将认为出现了拥塞导致丢包。
所以TCP判断拥塞就是判断有没有丢包
# 7.3 网络拥塞的表现?
主机ab通话,由主机a发送数据给主机b的时候不是直达,而是通过网络中的路由器等等,-----
路由器先储存这些数据,然后再从中取出,根据数据中的地址转发给下一个离主机b近的路由器或者直接到达主机b-----
有一个问题就是路由器的内存是有限的,如果同一时间到达的数据太多路由器接受不了就只能丢弃一部分,或者路由器数据本来就多后来的数据就要等很长时间才能转发
所以网络中数据太多,路由器处理不过来或者太慢就是网络拥塞
# 7.4 TCP/IP协议的拥塞控制?
TCP
进行拥塞控制的四种算法:慢开始、拥塞避免、快速重传、快速恢复。
- MSS:最大报文段长度,
TCP
双方发送的报文段中,包含的数据部分的最大字节数; - cwnd:拥塞窗口,
TCP
发送但还没有得到确认的报文的序号 都在这个区间; - RTT:往返时间,发送方发送一个报文,到接收这个报文的确认报文所经历的时间;
- ssthresh:慢开始门限值,慢开始阶段,若
cwnd
的大小达到这个值,将转换到拥塞避免模式;
三种模式要相互转换
例如初始cwnd=1 ssthresh=16
慢开始
慢开始
算法思想:当主机开始发送数据时,由于并不清楚网络的负荷情况,如果立即把大量数据字节注入到网络,那么就有可能引起网络发生拥塞,所以由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值,试探一下网络的拥塞情况。慢开始规定,在发送方每收到一个新的报文段的确认后,拥塞窗口的值就增大1,刚开始我们先设置拥塞窗口值为1,发送方收到一个新的确认报文之后,cwnd变为2,发送方接收到两个新的确认报文之后cwnd加2变成4。即拥塞窗口的增长每次都是收到确认报文段数量的2倍。为了防止拥塞窗口增长多大引起网络阻塞,为其设置了一个慢启动门限,当到达门限时,就进入到拥塞避免阶段每传一次数据cwnd指数增长:2、4、8、16
当cwnd=ssthresh=16的时候就变成拥塞避免
拥塞避免
拥塞避免
算法的思路:不再以指数形式增长拥塞窗口,而是每经过一个往返时间RTT就将发送方的拥塞窗口+1,使其增长缓慢,按照线性方式增长,如果发生网络拥塞,比如丢包时,就将慢启动门限设为原来的一半,然后将拥塞窗口设置为1,开始执行慢启动算法。这个时候每传一次数据cwnd+1,线性增长,当cwnd=24的时候如果一直没有接收到回应那可以认为发送拥塞了就会超时重传,这个时候
将慢开始门限值变为发生拥塞时cwnd的一半:ssthresh=cwnd/2=12,然后让cwnd减小为1重新开始慢启动算法,然后当cwnd=ssthresh=12的时候又开始拥塞避免
然后假如当cwnd=16的时候,接受到了同一个报文三次重复确认,但是也许并没有发生拥塞所以就启动快重传
快重传:
快速重传
算法思想:快速重传要求接收方不要等待自己发送数据时才进行捎带确认,而是要立即发送确认,即使收到了失序的报文段也要立即发出对已收到的报文段的重复确认。快速重传规定,发送方只要一连接收到3个重复确认,就知道接收方确实没有收到该报文段,因而应当立即进行重传,这样就不会出现超时,发送方也就不会误认为出现了网络拥塞。使用快速重传可以使整个网络的吞吐量提高约20%。快速重传后进入快速恢复。
快速重传的图解:
快速恢复
快速恢复
的思想:- 发送方将慢开始门限ssthresh值和拥塞窗口cwnd值调整为当前窗口的一半;不再执行慢启动而是直接进入拥塞避免阶段,使发送窗口成线性方式增长
- 也有的快速恢复实现是把快速恢复时的拥塞窗口cwnd值再增大一些(即3个报文段长度),即等于新的ssthresh+3个报文段长度。这样做的理由是,既然发送方收到3个重复的确认,就表明有3个报文段已经离开了网络。这3个报文段不再消耗网络的资源,而是停留在接收方的缓冲区种(接收方发送出了3个重复确认就证明了这个事实)。可见现在网络中并不是堆积了报文段,而是减少了3个报文段。因此可以适当的把拥塞窗口扩大些
# 8.ARP是地址解析协议,简单解释下工作原理
- 首先,每个主机都会在自己的ARP缓冲区中建立一个ARP列表,以表示IP地址和MAC地址之间的对应关系。
- 当源主机要发送数据时,首先检查ARP列表中是否有对应IP地址的目的主机的MAC地址,如果有,则直接发送数据,如果没有,就向本网段的所有主机发送ARP数据包,该数据包包括的内容有:源主机IP地址,源主机MAC地址,目的主机的IP地址。
- 当本网络的所有主机收到该ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址写入ARP响应包中,告诉源主机自己是它想要找的MAC地址。
- 源主机收到ARP响应包后。将目的主机的IP和MAC地址写入ARP列表,并利用此信息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
# 9.ICMP协议
ICMP是Internet Control Message Protocol,因特网控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息。控制消息是指网络通不通、主机是否可达、路由器是否可用等网络本身的消息。这些控制消息虽然并不传输用户数据,但是对于用户数据的传递起着重要的作用。ICMP报文有两种:差错报告报文和询问报文。
# 10.DHCP协议
动态主机配置协议,是一种让系统得以连接到网络上,并获取所需要的配置参数手段。通常被应用在大型的局域网络环境中,主要作用是集中的管理、分配IP地址,使网络环境中的主机动态的获得IP地址、Gateway地址、DNS服务器地址等信息,并能够提升地址的使用率。
# 11.TTL是什么?作用是什么?哪些工具会用到它?
TTL是指生存时间,简单来说,它表示了数据包在网络中的时间,经过一个路由器后TTL就减一,这样TTL最终会减为0,当TTL为0时,则将数据包丢弃,这样也就是因为两个路由器之间可能形成环,如果没有TTL的限制,则数据包将会在这个环上一直死转,由于有了TTL,最终TTL为0后,则将数据包丢弃。
使用TTL:
- ping发送数据包里面有TTL,但是并非是必须的,即是没有TTL也是能正常工作的
- traceroute正是因为有了TTL才能正常工作
- ifconfig是用来配置网卡信息的,不需要TTL
- netstat是用来显示路由表的,也是不需要TTL的
# 12.web页面的请求过程
Hey guys 各位读者姥爷们大家好,这里是程序员 cxuan 计算机网络连载系列的第 13 篇文章。
到现在为止,我们算是把应用层、运输层、网络层和数据链路层都介绍完了,那么现在是时候把这些内容都串起来,做一个全面的回顾了。那么我这就以 Web 页面的请求历程为例,来和你聊聊计算机网络中这些协议是怎样工作的、数据包是怎么收发的,从输入 URL 、敲击会车到最终完成页面呈现在你面前的这个过程。
首先,我打开了 Web Browser ,然后在 Google 浏览器 URL 地址栏中输入了 maps.google.com
。
然后 ......
# 12.1 查找 DNS 缓存
浏览器在这个阶段会检查四个地方是否存在缓存,第一个地方是浏览器缓存,这个缓存就是 DNS 记录。
浏览器会为你访问过的网站在固定期限内维护 DNS 记录。因此,它是第一个运行 DNS 查询的地方。 浏览器首先会检查这个网址在浏览器中是否有一条对应的 DNS 记录,用来找到目标网址的 IP 地址。
我是 chrome 浏览器,所以在 mac 中,无法使用 chrome://net-internals/#dns 找到对应的 IP 地址,在 windows 中是可以找到的。
那么 mac 怎么查询 DNS 记录呢?你可以使用
nslookup
命令来查找,但这不是我们讨论的重点。
DNS(Domain Name System)
是一个分布式的数据库,它用于维护网址 URL 到其 IP 地址的映射关系。在互联网中,IP 地址是计算机所能够理解的一种地址,而 DNS 的这种别名地址是我们人类能够理解和记忆的地址,DNS 就负责把人类记忆的地址映射成计算机能够理解的地址,每个 URL 都有唯一的 IP 地址进行对应。
举个例子,google 的官网是 www.google.com ,而 google 的 ip 地址是 216.58.200.228 ,这两个地址你在 URL 上输入哪个都能访问,但是 IP 地址不好记忆,而 google.com 简单明了。DNS 就相当于是我们几年前使用的家庭电话薄,比如你想给 cxuan 打电话,你有可能记不住 cxuan 的电话号码,此时你需要查询电话薄来找到 cxuan 的电话号码。
浏览器第二个需要检查的地方就是操作系统缓存。如果 DNS 记录不在浏览器缓存中,那么浏览器将对操作系统发起系统调用,Windows 下就是 getHostName
。
在 Linux 和大部分 UNIX 系统上,除非安装了
nscd
,否则操作系统可能没有 DNS 缓存。nscd 是 Linux 系统上的一种名称服务缓存程序。
浏览低第三个需要检查的地方是路由器缓存,如果 DNS 记录不在自己电脑上的话,浏览器就会和与之相连的路由器共同维护 DNS 记录。
如果与之相连的路由器也没有 DNS 记录的话,浏览器就会检查 ISP
中是否有缓存。ISP 缓存就是你本地通信服务商的缓存,因为 ISP 维护着自己的 DNS 服务器,它缓存 DNS 记录的本质也是为了降低请求时间,达到快速响应的效果。一旦你访问过某些网站,你的 ISP 可能就会缓存这些页面,以便下次快速访问。对于经常看小电影的你是否感到震惊呢?如果家里还安装了一个可以联网的摄像头的话,那就有点嗨皮了。
你肯定比较困惑为什么第一步浏览器需要检查这么多缓存,你可能会感到不舒服,因为缓存可能会透露我们的隐私,但是这些缓存在调节网络流量和缩短数据传输时间等方面至关重要。
所以,上面涉及到 DNS 缓存的查询过程如下。
如果上面四个步骤中都不存在 DNS 记录,那么就表示不存在 DNS 缓存,这个时候就需要发起 DNS 查询,以查找目标网址(本示例中是 maps.google.com)的 IP 地址。
# 12.2 发起 DNS 查询
如上所述,如果想要使我的计算机和 maps.google.com 建立连接并进行通信的话,我需要知道 maps.google.com 的 IP 地址,由于 DNS 的设计原因,本地 DNS 可能无法给我提供正确的 IP 地址,那么它就需要在互联网上搜索多个 DNS 服务器,来找到网站的正确 IP 地址。
这里有个疑问,为什么我需要搜索多个 DNS 服务器的来找到网站的 IP 地址呢?一台服务器不行吗?
因为 DNS 是分布式域名服务器,每台服务器只维护一部分 IP 地址到网络地址的映射,没有任何一台服务器能够维持全部的映射关系。
在 DNS 的早期设计中只有一台 DNS 服务器。这台服务器会包含所有的 DNS 映射。这是一种集中式
的设计,这种设计并不适用于当今的互联网,因为互联网有着数量巨大并且持续增长的主机,这种集中式的设计会存在以下几个问题
单点故障(a single point of failure)
,如果 DNS 服务器崩溃,那么整个网络随之瘫痪。通信容量(traaffic volume)
,单个 DNS 服务器不得不处理所有的 DNS 查询,这种查询级别可能是上百万上千万级,一台服务器很难满足。远距离集中式数据库(distant centralized database)
,单个 DNS 服务器不可能邻近
所有的用户,假设在美国的 DNS 服务器不可能临近让澳大利亚的查询使用,其中查询请求势必会经过低速和拥堵的链路,造成严重的时延。维护(maintenance)
,维护成本巨大,而且还需要频繁更新。
所以在当今网络情况下 DNS 不可能集中式设计,因为它完全没有可扩展能力,所以采用分布式设计
,这种设计的特点如下
分布式、层次数据库。
首先分布式设计首先解决的问题就是 DNS 服务器的扩展性问题,因此 DNS 使用了大量的 DNS 服务器,它们的组织模式一般是层次方式,并且分布在全世界范围内。没有一台 DNS 服务器能够拥有因特网上所有主机的映射。相反,这些映射分布在所有的 DNS 服务器上。
大致来说有三种 DNS 服务器:根 DNS 服务器
、 顶级域(Top-Level Domain, TLD) DNS 服务器
和 权威 DNS 服务器
。这些服务器的层次模型如下图所示
根 DNS 服务器
,有 400 多个根域名服务器遍及全世界,这些根域名服务器由 13 个不同的组织管理。根域名服务器的清单和组织机构可以在 https://root-servers.org/ 中找到,根域名服务器提供 TLD 服务器的 IP 地址。顶级域 DNS 服务器
,对于每个顶级域名比如 com、org、net、edu 和 gov 和所有的国家级域名 uk、fr、ca 和 jp 都有 TLD 服务器或服务器集群。所有的顶级域列表参见 https://tld-list.com/ 。TDL 服务器提供了权威 DNS 服务器的 IP 地址。权威 DNS 服务器
,在因特网上具有公共可访问的主机,如 Web 服务器和邮件服务器,这些主机的组织机构必须提供可供访问的 DNS 记录,这些记录将这些主机的名字映射为 IP 地址。一个组织机构的权威 DNS 服务器收藏了这些 DNS 记录。
在了解了 DNS 服务器的设计理念之后,我们回到 DNS 查找的步骤上来,DNS 的查询方式主要分为三种
DNS 查找中会出现三种类型的查询。通过组合使用这些查询,优化的 DNS 解析过程可缩短传输距离。在理想情况下,可以使用缓存的记录数据,从而使 DNS 域名服务器能够直接使用非递归查询。
递归查询
:在递归查询中,DNS 客户端要求 DNS 服务器(一般为 DNS 递归解析器)将使用所请求的资源记录响应客户端,或者如果解析器无法找到该记录,则返回错误消息。
迭代查询
:在迭代查询中,如果所查询的 DNS 服务器与查询名称不匹配,则其将返回对较低级别域名空间具有权威性的 DNS 服务器的引用。然后,DNS 客户端将对引用地址进行查询。此过程继续使用查询链中的其他 DNS 服务器,直至发生错误或超时为止。
非递归查询
:当 DNS 解析器客户端查询 DNS 服务器以获取其有权访问的记录时通常会进行此查询,因为其对该记录具有权威性,或者该记录存在于其缓存内。DNS 服务器通常会缓存 DNS 记录,查询到来后能够直接返回缓存结果,以防止更多带宽消耗和上游服务器上的负载。
上面负责开始 DNS 查找的介质就是 DNS 解析器,它一般是 ISP 维护的 DNS 服务器,它的主要职责就是通过向网络中其他 DNS 服务器询问正确的 IP 地址。
如果想要了解更多关于 DNS 的消息,请查阅 万字长文爆肝 DNS 协议! (opens new window)
所以对于 maps.google.com 这个域名来说,如果 ISP 维护的服务器没有 DNS 缓存记录,它就会向 DNS 根服务器地址发起查询,根名称服务器会将其重定向到 .com 顶级域名服务器。 .com 顶级域名服务器会将其重定向到google.com 权威服务器。google.com 名称服务器将在其 DNS 记录中找到 maps.google.com 匹配的 IP 地址,并将其返回给您的 DNS 解析器,然后将其发送回你的浏览器。
这里值得注意的是,DNS 查询报文会经过许多路由器和设备才会达到根域名等服务器,每经过一个设备或者路由器都会使用路由表
来确定哪种路径是数据包达到目的地最快的选择。这里面涉及到路由选择算法,如果小伙伴们想要了解路由选择算法,可以看看这篇文章 https://www.cisco.com/c/en/us/support/docs/ip/border-gateway-protocol-bgp/13753-25.html#anc3
# 12.3 ARP 请求
我看了很多篇文章都没有提到这一点,那就是 ARP 请求的这个过程。
什么时候需要发送 ARP 请求呢?
这里其实有个前提条件
- 如果 DNS 服务器和我们的主机在同一个子网内,系统会按照下面的 ARP 过程对 DNS 服务器进行 ARP 查询
- 如果 DNS 服务器和我们的主机在不同的子网,系统会按照下面的 ARP 过程对默认网关进行查询
ARP 协议的全称是 Address Resolution Protocol(地址解析协议)
,它是一个通过用于实现从 IP 地址到 MAC 地址的映射,即询问目标 IP 对应的 MAC 地址 的一种协议。
简而言之,ARP 就是一种解决地址问题的协议,它以 IP 地址为线索,定位下一个应该接收数据分包的主机 MAC 地址。如果目标主机不在同一个链路上,那么会查找下一跳路由器的 MAC 地址。
关于为什么有了 IP 地址,还要有 MAC 地址概述可以参看知乎这个回答 https://www.zhihu.com/question/21546408
ARP 的大致工作流程如下
假设 A 和 B 位于同一链路,不需要经过路由器的转换,主机 A 向主机 B 发送一个 IP 分组,主机 A 的地址是 192.168.1.2 ,主机 B 的地址是 192.168.1.3,它们都不知道对方的 MAC 地址是啥,主机 C 和 主机 D 是同一链路的其他主机。
主机 A 想要获取主机 B 的 MAC 地址,通过主机 A 会通过广播
的方式向以太网上的所有主机发送一个 ARP 请求包
,这个 ARP 请求包中包含了主机 A 想要知道的主机 B 的 IP 地址的 MAC 地址。
主机 A 发送的 ARP 请求包会被同一链路上的所有主机/路由器接收并进行解析。每个主机/路由器都会检查 ARP 请求包中的信息,如果 ARP 请求包中的目标 IP 地址
和自己的相同,就会将自己主机的 MAC 地址写入响应包返回主机 A
由此,可以通过 ARP 从 IP 地址获取 MAC 地址,实现同一链路内的通信。
所以,要想发送 ARP 广播,我们需要有一个目标 IP 地址,同时还需要知道用于发送 ARP 广播的接口的 MAC 地址。
这里会涉及到 ARP 缓存的概念。
现在你知道了发送一次 IP 分组前通过发送一次 ARP 请求就能够确定 MAC 地址。那么是不是每发送一次都得经过广播 -> 封装 ARP 响应 -> 返回给主机这一系列流程呢?
想想看,浏览器是如何做的?浏览器内置了缓存能够缓存你最近经常使用的地址,那么 ARP 也是一样的。ARP 高效运行的关键就是维护每个主机和路由器上的 ARP 缓存(或表)
。这个缓存维护着每个 IP 到 MAC 地址的映射关系。通过把第一次 ARP 获取到的 MAC 地址作为 IP 对 MAC 的映射关系到一个 ARP 缓存表中,下一次再向这个地址发送数据报时就不再需要重新发送 ARP 请求了,而是直接使用这个缓存表中的 MAC 地址进行数据报的发送。每发送一次 ARP 请求,缓存表中对应的映射关系都会被清除。
通过 ARP 缓存,降低了网络流量的使用,在一定程度上防止了 ARP 的大量广播。
一般来说,发送过一次 ARP 请求后,再次发送相同请求的几率比较大,因此使用 ARP 缓存能够减少 ARP 包的发送,除此之外,不仅仅 ARP 请求的发送方能够缓存 ARP 接收方的 MAC 地址,接收方也能够缓存 ARP 请求方的 IP 和 MAC 地址,如下所示
不过,MAC 地址的缓存有一定期限,超过这个期限后,缓存的内容会被清除。
深入理解 ARP 协议的话,可以参考 cxuan 的这篇文章。
ARP,这个隐匿在计网背后的男人 (opens new window)
所以,浏览器会首先查询 ARP 缓存,如果缓存命中,我们返回结果:目标 IP = MAC。
如果缓存没有命中:
- 查看路由表,看看目标 IP 地址是不是在本地路由表中的某个子网内。是的话,使用跟那个子网相连的接口,否则使用与默认网关相连的接口。
- 查询选择的网络接口的 MAC 地址
- 我们发送一个数据链路层的 ARP 请求:
根据连接主机和路由器的硬件类型不同,可以分为以下几种情况:
直连:
- 如果我们和路由器是直接连接的,路由器会返回一个
ARP Reply
(见下面)。
集线器:
- 如果我们连接到一个集线器,集线器会把 ARP 请求向所有其它端口广播,如果路由器也连接在其中,它会返回一个
ARP Reply
。
交换机:
- 如果我们连接到了一个交换机,交换机会检查本地 CAM/MAC 表,看看哪个端口有我们要找的那个 MAC 地址,如果没有找到,交换机会向所有其它端口广播这个 ARP 请求。
- 如果交换机的 MAC/CAM 表中有对应的条目,交换机会向有我们想要查询的 MAC 地址的那个端口发送 ARP 请求
- 如果路由器也
连接
在其中,它会返回一个ARP Reply
ARP Reply
:
现在我们有了 DNS 服务器或者默认网关的 IP 地址,我们可以继续 DNS 请求了:
- 使用 53 端口向 DNS 服务器发送 UDP 请求包,如果响应包太大,会使用 TCP 协议
- 如果本地/ISP DNS 服务器没有找到结果,它会发送一个递归查询请求,一层一层向高层 DNS 服务器做查询,直到查询到起始授权机构,如果找到会把结果返回。
(上述均来自:https://github.com/skyline75489/what-happens-when-zh_CN#dns)
# 12.4 封装 TCP 数据包
浏览器得到目标服务器的 IP 地址后,根据 URL 中的端口可以知道端口号 (http 协议默认端口号是 80, https 默认端口号是 443),会准备 TCP 数据包。数据包的封装会经过下面的层层处理,数据到达目标主机后,目标主机会解析数据包,完整的请求和解析过程如下。
这里就不再详细介绍了,读者朋友们可以阅读 cxuan 的这篇文章 TCP/IP 基础知识详解 (opens new window)详细了解。
# 12.5 浏览器与目标服务器建立 TCP 连接
在经过上述 DNS 和 ARP 查找流程后,浏览器就会收到一个目标服务器的 IP 和 MAC地址,然后浏览器将会和目标服务器建立连接来传输信息。这里可以使用很多种 Internet 协议,但是 HTTP 协议建立连接所使用的运输层协议是 TCP 协议。所以这一步骤是浏览器与目标服务器建立 TCP 连接的过程。
TCP 的连接建立需要经过 TCP/IP 的三次握手,三次握手的过程其实就是浏览器和服务器交换 SYN 同步和 ACK 确认消息的过程。
假设图中左端是客户端主机,右端是服务端主机,一开始,两端都处于CLOSED(关闭)
状态。
- 服务端进程准备好接收来自外部的 TCP 连接。然后服务端进程处于
LISTEN
状态,等待客户端连接请求。 - 客户端向服务器发出连接请求,请求中首部同步位 SYN = 1,同时选择一个初始序号 sequence ,简写 seq = x。SYN 报文段不允许携带数据,只消耗一个序号。此时,客户端进入
SYN-SEND
状态。 - 服务器收到客户端连接后,,需要确认客户端的报文段。在确认报文段中,把 SYN 和 ACK 位都置为 1 。确认号是 ack = x + 1,同时也为自己选择一个初始序号 seq = y。请注意,这个报文段也不能携带数据,但同样要消耗掉一个序号。此时,TCP 服务器进入
SYN-RECEIVED(同步收到)
状态。 - 客户端在收到服务器发出的响应后,还需要给出确认连接。确认连接中的 ACK 置为 1 ,序号为 seq = x + 1,确认号为 ack = y + 1。TCP 规定,这个报文段可以携带数据也可以不携带数据,如果不携带数据,那么下一个数据报文段的序号仍是 seq = x + 1。这时,客户端进入
ESTABLISHED (已连接)
状态 - 服务器收到客户的确认后,也进入
ESTABLISHED
状态。
这样三次握手建立连接的阶段就完成了,双方可以直接通信了。
# 12.6 浏览器发送 HTTP 请求到 web 服务器
一旦 TCP 连接建立完成后,就开始直接传输数据办正事了!此时浏览器会发送 GET
请求,要求目标服务器提供 maps.google.com 的网页,如果你填写的是表单,则发起的是 POST
请求,在 HTTP 中,GET 请求和 POST 请求是最常见的两种请求,基本上占据了所有 HTTP 请求的九成以上。
除了请求类型外,HTTP 请求还包含很多很多信息,最常见的有 Host、Connection 、User-agent、Accept-language 等
首先 Host 表示的是对象所在的主机。Connection: close
表示的是浏览器需要告诉服务器使用的是非持久连接
。它要求服务器在发送完响应的对象后就关闭连接。User-agent
: 这是请求头用来告诉 Web 服务器,浏览器使用的类型是 Mozilla/5.0
,即 Firefox 浏览器。Accept-language
告诉 Web 服务器,浏览器想要得到对象的法语版本,前提是服务器需要支持法语类型,否则将会发送服务器的默认版本。下面我们针对主要的实体字段进行介绍(具体的可以参考 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers MDN 官网学习)
HTTP 的请求标头分为四种: 通用标头
、请求标头
、响应标头
和 实体标头
。
这四种标头又分别有很多内容,如果你想要深入理解一下关于 HTTP 请求头的相关内容,可以参考 cxuan 的这篇文章
深入理解 HTTP 标头 (opens new window)
# 12.7 服务器处理请求并发回一个响应
这个服务器包含一个 Web 服务器,也就是 Apache 服务器,服务器会从浏览器接收请求并将其传递给请求处理程序并生成响应。
请求处理程序也是一个程序,它一般是用 .net 、php、ruby 等语言编写,用于读取请求,检查请求内容,cookie,必要时更新服务器上的信息的这么一个程序。它会以特定的格式比如 JSON、XML、HTML 组合响应。
# 12.8 服务器发送回一个 HTTP 响应
服务器响应包含你请求的网页以及状态代码,压缩类型(Content-Encoding),如何缓存页面(Cache-Control),要设置的 cookie,隐私信息等。
比如下面就是一个响应体
关于深入理解 HTTP 请求和响应,可以参考这篇文章
看完这篇HTTP,跟面试官扯皮就没问题了 (opens new window)
# 12.9 浏览器显示 HTML 的相关内容
浏览器会分阶段显示 HTML 内容。 首先,它将渲染裸露的 HTML 骨架。 然后它将检查 HTML 标记并发送 GET 请求以获取网页上的其他元素,例如图像,CSS 样式表,JavaScript 文件等。这些静态文件由浏览器缓存,因此你再次访问该页面时,不用重新再请求一次。最后,您会看到 maps.google.com 显示的内容出现在你的浏览器中。
# 13.DNS(Domain Name System)
当我们在浏览器的地址栏输入域名时,用户主机会首先在自己的DNS高速缓存中查找该域名所对应的IP地址,如果没有找到,则会向网络中的某台DNS服务器中有域名和IP地址映射关系的数据库,当DNS服务器收到DNS查询报文后,在其数据库中进行查询,之后将查询结果发送给用户主机,主机中的浏览器就可以通过web服务器的IP地址对其进行访问了
# 13.1概要
因特网采用
层次树状结构的域名结构
域名的结构由若干个分量组成,各分量之间用"点"隔开,分别代表不同级别的域名
- 每一级的域名都由英文字母和数字组成,不超过63个字符,不区分大小写字母
- 级别最低的域名写在最左边,而级别最高的顶级域名写在最右边
- 完整的域名不超过255个字符
域名系统既不规定一个域名需要包含多少个夏季域名,也不规定每一级的域名代表什么意思
各级域名由其上一级的域名管理结构管理,而最高的顶级域名则由因特网名与数字地址分配机构ICANN进行管理。
# 13.2域名结构:
# 13.3域名空间:
# 13.4域名划分
域名和IP地址的映射关系必须保存在域名服务器中,供所有其他应用查询。显然不能将所有信息都储存在一台域名服务器中。DNS使用分布在各地的域名服务器来实现域名到IP地址的转换。
域名服务器可以划分为以下四种不同的类型:
根域名服务器
根域名服务器是最高层次的域名服务器。每个根域名服务器都知道所有的顶级域名服务器的域名及其IP地址。因特网上共有13个不同IP地址的根域名服务器。尽管我们将这13个根域名服务器中的每一个都视为单个的服务器,但“每台服务器”实际上是由许多分布在世界各地的计算机构成的服务器群集。当本地域名服务器向根域名服务器发出查询请求时,路由器就把查询请求报文转发到离这个DNS客户最近的一个根域名服务器。这就加快了DNS的查询过程,同时也更合理地利用了因特网的资源。
根域名服务器通常并不直接对城名进行解析,而是返回该域名所属顶级域名的顶级域名服务器的IP地址
。顶级域名服务器
这些域名服务器负责
管理在该顶级域名服务器注册的所有二级域名
。当收到DNS查询请求时就给出相应的回答((可能是最后的结果,也可能是下一级权限域名服务器的IP地址)。权限域名服务器
这些域名服务器负责
管理某个区
的域名。每一个主机的域名都必须在某个权限域名服务器处注册登记。因此权限域名服务器知道其管辖的域名与IP地址的映射关系。另外,权限域名服务器还知道其下级域名服务器的地址。本地域名服务器
本地域名服务器不属于上述的域名服务器的等级结构。当一个主机发出DNS请求报文时,这个报文就首先被送往该主机的本地域名服务器。
本地域名服务器起着代理的作用,会将该报文转发到上述的域名服务器的等级结构中
。每一个因特网服务提供者ISP,一个大学,甚至一个大学里的学院,都可以拥有一个本地域名服务器,它有时也称为默认域名服务器
。本地域名服务器离用户较近,一般不超过几个路由器的距离,也有可能就在同一个局域网中。本地域名服务器的IP地址需要直接配置在需要域名解析的主机中。
# 13.5域名解析的过程
递归查询
迭代查询
为了提高DNS的查询效率,并减轻根域名服务器的负荷和减少因特网上的DNS查询报文数量,在域名服务器中广泛地使用了高速缓存。高速缓存用来存放最近查询过的域名以及从何处获得域名映射信息的记录。
由于域名到IP地址的映射关系并不是永久不变,为保持告诉缓存中的内容正确,域名服务器
应为每项内容设置计时器并删除超过合理时间的项
(例如,每个项目只存放两天)
不但在本地域名服务器中需要高速缓存,在用户主机中也很需要。许多用户主机在启动时从本地域名服务器下载域名和IP地址的全部数据库,维护存放自己最近使用的域名的高速缓存,并且只在从缓存中找不到域名时才向域名服务器查询。同理,主机也需要保持高速缓存中内容的正确性。