0%

计算机网络

1. get请求和post请求的区别

GETPOST是 HTTP 协议中两种常用的请求方法,使用它们都可以跟服务器进行通讯,它们区别有以下几点:

  • 一般来说GET主要用来请求资源,而POST一般用于提交数据到服务器。因此对于GET来说如果有参数传递的话,会将参数直接拼接到URL(资源定位符)上;而对于POST来说,这些参数会写在请求消息体中。因此对于要传输一些敏感信息的话,get方法不是安全的,这种情况使用POST更好。
  • 此外,由于URL有长度限制,因此对于GET来说,其传递的数据长度会受到浏览器的限制(2048),而POST将数据放在消息体中,因此通常没有数据长度限制。
  • 还有就是GET方法得到常见如HTML、JS或者CSS这些资源会被浏览器缓存,如果下次传输的数据相同,那么他们就会返回缓存中的内容,以求更快的展示所需要的数据;而对于POST来说,Post请求不会进行缓存操作。
  • 另外呢GET产生一个TCP数据包,而POST可能会产生两个数据包(不是必然),浏览器回先发送header,服务器响应100 continue后再发送data数据包,因此,Post在时间上的消耗一般会被Get要大
  • Get请求可以直接进行回退和刷新,不会对用户和程序产生影响,但POST请求如果直接回滚和刷新的将会重新把数据提交。(缓存)

2. TCP和UDP的区别

  • 连接性:TCP是面向连接的传输层协议,即传输数据之前必须先建立好连接。UDP无连接。
  • 服务对象:TCP是点对点的两点间服务,即一条TCP连接只能有两个端点;UDP支持一对一,一对多,多对一,多对多的交互通信。
  • 可靠性:TCP是有保证数据安全可靠的措施,可靠交付:无差错,不丢失,不重复,按序到达。UDP是尽最大努力交付,不保证可靠交付。
  • 拥塞控制和流量控制:TCP有拥塞控制和流量控制保证数据传输的安全性。UDP没有拥塞控制,网络拥塞不会影响源主机的发送效率。
  • 报文长度:TCP是动态报文长度,即TCP报文长度是根据接收方的窗口大小和当前网络拥塞情况决定的。UDP面向报文,不合并,不拆分,保留上面传下来报文的边界。
  • 首部开销:TCP首部开销大,首部20个字节。UDP首部开销小,8字节。(源端口,目的端口,数据长度,校验和)
  • TCP和UDP适用场景:从特点上我们已经知道,TCP是可靠的但传输速度慢,UDP 是不可靠的但传输速度快。因此在选用具体协议通信时,应该根据通信数据的要求而决定。

若通信数据完整性需让位与通信实时性,则应该选用TCP 协议(如文件传输、重要状态的更新等);反之,则使用 UDP 协议(如视频传输、实时通信等)。 TCP的各个字段有着不同的作用,对于TCP来说,最重要的就是序列号(seq)、确认序列号(ack)、控制位、窗口大小、校验和和紧急指针。它们的作用如下:

  • 序列号:报文的序列号,标识TCP发端向TCP接收端发送的数据字节流
  • 确认序列号:如果设定了ACK,那么从这个字段包含了接收放期望从发送方接收到的下一个数据字节的序列号
  • 首部长度:该字段标识了TCP报文首部长度,该字段4个比特网位,则表示首部长度最大可达60字节
  • 保留位:该字段有4位未使用的比特位
  • 控制位:用来指示相应字段是否有效,主要包括以下控制位:
    • CWR:拥塞窗口减小标记
    • ECE:显示的拥塞通知回显标记
    • URG:若设置了该位,则紧急指针字段包含的信息有效
    • ACK:若设置了该位,则确认序列号字段包含的信息有效
    • PSH:将所有收到的数据发送接收的进程
    • RST:重置连接
    • SYN:同步序列号
    • FIN:发送端提示已经完成了发送任务
  • 窗口大小:该字段用在接收端发送ACK确认时提示自己可接受数据的空间大小
  • 校验和:16位的检验,通过在首部添加一些位,在接收端通过CRC校验和来判断数据在传输过程中是否发生错误
  • 紧急指针:告诉接收端数据包应该马上向上交付给应用层。

3. TCP三次握手

  • 只有SYN位置1表示连接请求。
  • 只有ACK置1表示ACK报文段,携带数据时会消耗序号seq,不携带则不消耗
  • ACKSYN都置1,不能携带数据,但消耗1个序号seq
3.1 三次握手
  • 1、Client将标志位SYN置为1,随机产生一个序号值seq=J,并将该数据包发送给Server,Client进入SYN_SENT状态,等待Server确认。
  • 2、Server收到数据包后由标志位SYN=1知道Client请求建立连接,Server将标志位SYNACK都置为1,ack=J+1,随机产生一个值seq=K,并将该数据包发送给Client以确认连接请求,Server进入SYN_RCVD状态。
  • 3、Client收到确认后,检查ack是否为J+1,ACK若为1,如果正确则将标志位ACK置为1,ack=K+1,并将该数据包发送给Server,Server检查ack是否为K+1,ACK为1,如果正确则连接建立成功,Client和Server进入ESTABLISHED状态,完成三次握手,随后Client与Server之间可以开始传输数据了。

tip:注意前两次握手不能携带数据,这是为什么呢?因为前两次双方的状态都不是处于ESTABLISHED连接建立的状态,只要第三次时,客户端已处于已建立连接状态

3.2 三次握手出现的一些错误怎么办
  • ①第一次握手失败:
    • 第一次握手失败由于服务器并没有收到任何消息,因此不会有任何反应,而客户端由于长时间没有收到答复,触发超时重传机制重发ACK数据包。(超时重传机制有次数限制,单个包不能重传超5次)
  • ②第二次握手失败:
    • 客户端:久久没有收到服务器的SYS/ACK包,则超时重传请求连接包
    • 服务器:服务器是发送了SYS/ACK处于SYN_RCVD状态,由于久久没有收到ACK回复,则也好触发超时重传,重传SYN/ACK
  • ③第三次握手失败:
    • 若客户端先发送数据包:第三次握手失败,由于客户端已经处于ESTABILSHED状态,后续它可以发送一些请求数据的包给服务器,服务器收到这些请求数据的包,但是服务器还未收到ACK确认报文,还未处于ESTABILSHED状态,因此会回发一个连接异常包,通知客户端重新建立连接,此时包的RST重置连接位会置1
    • 若客户端发送数据包给服务器:服务器是发送了SYS/ACK处于SYN_RCVD状态,由于久久没有收到ACK回复,则也好触发超时重传,重传SYN/ACK
  • ④第三次要回ACK的原因:
    • 如果没有第三次回ACK,会导致已经失效的连接请求报文突然又传输到服务器端,又建立客户端与服务器的连接,但客户端又不发送数据,此时导致的服务器资源浪费。 所谓已经失效的连接请求是指客户端发出的连接请求滞留在网络中,超时后但又被服务器接收到。
    • 第三次握手失败(超时)时,服务器并重传一定次数的 SYN/ACK 报文,如果重传机制过完还没有收到,则server 会发送 RTS 复位报文段并主动关闭至closed,以防止 syn 洪泛攻击。

syn洪泛攻击:通俗的理解是,当第三次握手没有发送确认信息时,等待一段时间后,主机就会断开之前的半开连接并回收资源。如果不这样做将会为 dos(deny of service) 攻击埋下隐患,当主动方主动发送大量的 syn 数据包,但并不做出第三次握手响应,server 就会为这些 syn 包分配资源(但并未使用),就会使 server 占用大量内存,使 server 连接环境耗尽,这就是 syn 洪泛攻击

  • ⑤为什么要三次?一次、两次握手不可以吗?
    • 假如可以一次握手:这将致服务器于危险处境——SYN洪泛攻击。如果存在恶意用户发送大量的虚假连接请求,会导致服务器疲于应付无用的连接请求,消耗系统资源,无法为正常用户提供服务。

    • 假如可以两次握手:考虑这样一个场景,假如客户端发送了两个请求连接阻塞在网络中。其中第一个丢失,第二个到达了服务端。但是第一个丢失的报文段只是在某些网络结点长时间滞留了,延误到连接释放以后的某个时间才到达服务端,此时服务端误认为客户端又发出一次新的连接请求,于是就向客户端发出确认报文段,此时没有三次握手,双方就建立新的连接了,此时客户端忽略服务端发来的确认,也不发送数据,则服务端一致等待客户端发送数据,浪费资源。
    • 另外,TCP的序列号是保证可靠性的关键因素,通过序列号接收方可以去除重复数据和通知发送方你需要的下一个数据序列号是什么,同时接收方可以根据数据包的序列号按序接收;同样通过ACK包发送方知道哪些数据包已被接受,因此三次握手是保证序列号同步的必须的步骤。

3.3 思考:connect为什么会阻塞(即第三次ACK丢失下客户端怎么办)

server端:

第三次的ACK在网络中丢失,那么Server端该TCP连接的状态为SYN_RECV,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包,以便Client重新发送ACK包。 而Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为>5.如果重发指定次数之后,仍然未收到 client 的ACK应答,那么一段时间后,Server自动关闭这个连接。

client端

在linux c 中,client 一般是通过connect()函数来连接服务器的,而connect()是在TCP的三次握手的第二次握手完成后就成功返回值。也就是说client在接收到 SYN+ACK包,它的TCP连接状态就为established (已连接),表示该连接已经建立。 那么如果第三次握手中的ACK包丢失的情况下,Client 向server端发送数据,Server端将以RST包响应,方能感知到Server的错误。

4. TCP四次挥手

由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN 只是意味着这一方向上没有数据流动了,即不会再发送到数据了,但是在这个TCP连接上仍然能够收数据,直到另一方也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

4.1 四次挥手过程
  • 1.数据传输结束后,客户端的应用进程发出连接释放FIN报文段,并停止发送数据,客户端进入FIN_WAIT_1状态,此时客户端依然可以接收服务器发送来的数据。
  • 2.服务器接收到FIN后,发送一个ACK给客户端,确认序号为收到的序号+1,服务器进入CLOSE_WAIT状态。客户端收到后进入FIN_WAIT_2状态。
  • 3.当服务器没有数据要发送时,服务器也发送一个FIN报文,此时服务器进入LAST_ACK状态,等待客户端的确认
  • 4.客户端收到服务器的FIN报文后,给服务器发送一个ACK报文,确认序列号为收到的序号+1。此时客户端进入TIME_WAIT状态,等待2MSL(MSL:报文段最大生存时间),然后关闭连接。

应用层可以使用系统调用函数read函数==0来判断对端是否关闭连接。

4.2 为什么要等待2MSL才关闭链接(也是为什么

MSL是报文在网络的最大生存时间

  • ①为保证客户端发送的最后一个ACK报文段能够到达服务器。若第4次挥手的报文段丢失了,服务器还有时间触发超时重传第3次挥手的报文段,即保证被动关闭的一方也能被正确的关闭(如果重传到达一定数量,服务器就直接关闭该连接)
  • ②经过2MSL时间,可以使本次连接持续时间内所以产生的报文段(主要针对滞留在网络中的)都失效,这样就可避免已失效的本次连接中的所有请求影响下一次连接。
4.3 为什么要4次挥手

因为主动关闭的一方是已经确定没有数据要发送了,而被动关闭的一方还未FIN报文,先回一个ACK确认报文,其在FIN发生前可能还要发送数据,只有等待数据发生完,才能回一个FIN报文,主动关闭方再回一个ACK确认,才能达到双向关闭,

4.4 TIME_WAIT过多有什么危害?

这要分角色来看待,TIME_WAIT状态是主动关闭的一方才会出现的状态,若在客户端则是客户端主动关闭,若在服务器则服务器执行主动关闭:

  • 如果客户端(主动发起关闭连接方)的 TIME_WAIT 状态过多:占满了所有端口资源,那么就无法对「目的 IP+ 目的 PORT」都一样的服务端发起连接了,但被使用的端口是可以继续对另外一个ip地址不一样服务端发起连接的

  • 如果服务端(主动发起关闭连接方)的 TIME_WAIT 状态过多,并不会导致端口资源受限,因为服务端只监听一个端口,但是 TCP 连接过多,会占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等等

4.5 服务器出现大量 TIME_WAIT 状态的原因有哪些?

首先要知道 TIME_WAIT 状态是主动关闭连接方才会出现的状态,所以如果服务器出现大量的 TIME_WAIT 状态的 TCP 连接,就是说明服务器主动断开了很多 TCP 连接。

问题来了,什么场景下服务端会主动断开连接呢?

  • 第一个场景:HTTP 没有使用长连接,频繁的连接建立和断开:
  • 第二个场景:HTTP 长连接超时
  • 第三个场景:HTTP 长连接的请求数量达到上限

解决:

  • 使用负载均衡转发连接:将连接分摊到多台服务器上,减少每台服务器上的TIME_WAIT状态数量。
  • 使用TCP快速回收:在系统内核中设置TCP快速回收,可以减少TIME_WAIT状态的存在时间。

5. TCP机的状态转移

[^上半部分为3次握手,下半部分为4次挥手,实线表示主动,虚线为被动,细线为特殊情况]

状态解释:

  • CLOSED:表示初始状态。
  • LISTEN:该状态表示服务器端的某个SOCKET处于监听状态,可以接受连接。
  • SYN_SENT:这个状态与SYN_RCVD遥相呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,随即进入到了SYN_SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN_SENT状态表示客户端已发送SYN报文。
  • SYN_RCVD: 该状态表示接收到SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂。此种状态时,当收到客户端的ACK报文后,会进入到ESTABLISHED状态。
  • ESTABLISHED:表示连接已经建立。

  • FIN_WAIT_1: FIN_WAIT_1和FIN_WAIT_2状态的真正含义都是表示等待对方的FIN报文。区别是:
    • FIN_WAIT_1状态是当socket在ESTABLISHED状态时,想主动关闭连接,向对方发送了FIN报文,此时该socket进入到FIN_WAIT_1状态。
    • FIN_WAIT_2状态是当对方回应ACK后,该socket进入到FIN_WAIT_2状态,正常情况下,对方应马上回应ACK报文,所以FIN_WAIT_1状态一般较难见到,而FIN_WAIT_2状态可用netstat看到。
  • FIN_WAIT_2主动关闭链接的一方,发出FIN收到ACK以后进入该状态。称之为半连接或半关闭状态。该状态下的socket只能接收数据,不能发,既socket上还有数据流动。

  • TIME_WAIT: 表示收到了对方的FIN报文,并发送出了ACK报文,等2MSL后即可回到CLOSED可用状态。如果FIN_WAIT_1状态下,收到对方同时带FIN标志和ACK标志的报文时,可以直接进入到TIME_WAIT状态,而无须经过FIN_WAIT_2状态。

  • CLOSING: 这种状态较特殊,属于一种较罕见的状态。正常情况下,当你发送FIN报文后,按理来说是应该先收到(或同时收到)对方的 ACK报文,再收到对方的FIN报文。但是CLOSING状态表示你发送FIN报文后,并没有收到对方的ACK报文,反而却也收到了对方的FIN报文。什么情况下会出现此种情况呢?如果双方几乎在同时close一个SOCKET的话,那么就出现了双方同时发送FIN报文的情况,也即会出现CLOSING状态,表示双方都正在关闭SOCKET连接。

  • CLOSE_WAIT: 此种状态表示在等待关闭。当对方关闭一个SOCKET后发送FIN报文给自己,系统会回应一个ACK报文给对方,此时则进入到CLOSE_WAIT状态。接下来呢,察看是否还有数据发送给对方,如果没有可以 close这个SOCKET,发送FIN报文给对方,即关闭连接。所以在CLOSE_WAIT状态下,需要关闭连接。(服务器)
  • LAST_ACK: 该状态是被动关闭一方在发送FIN报文后,最后等待对方的ACK报文。当收到ACK报文后,即可以进入到CLOSED可用状态。(服务器)

6. TCP的拥塞控制:对整个网络

拥塞控制是防止过多的数据注入网络,使得网络中的路由器或者链路过载。流量控制是点对点的通信量控制,而拥塞控制是全局的网络流量整体性的控制。发送双方都有一个拥塞窗口cwnd

  • 慢开始:最开始发送方的拥塞窗口为1,由小到大逐渐增大发送窗口和拥塞窗口。每经过一个传输轮次,拥塞窗口cwnd加倍。当cwnd超过慢开始门限,则使用拥塞避免算法,避免cwnd增长过大。

  • 拥塞避免:每经过一个往返时间RTTcwnd只增长1。在慢开始和拥塞避免的过程中,一旦发现网络拥塞(超时),就把慢开始门限设为当前值的一半,并且重新设置cwnd为1,重新慢启动。(乘法减小,加法增大)

  • 快重传:接收方每次收到一个失序的报文段后就立即发出重复确认,发送方只要连续收到三个重复确认就立即重传(尽早重传未被确认的报文段)。

  • 快恢复:当发送方连续收到了三个重复确认,就乘法减半(慢开始门限减半),并将当前的cwnd设置为慢开始门限,并且采用拥塞避免算法(连续收到了三个重复请求,说明当前网络可能没有拥塞)。

7. TCP的可靠性保证

TCP主要提供了检验和、序列号/确认应答、超时重传、最大消息长度、滑动窗口控制等方法实现了可靠性传输。

  • 序列号/确认应答:TCP报文中有序列号和确认序列号,对于接收和发送都具有缓存区的性质,保证了数据能够丢失重传和解决包乱序的问题。

  • 检验和:通过检验和的方式,接收端可以检测出来数据是否有差错和异常,假如有差错就会直接丢弃TCP段,重新发送。TCP在计算检验和时,会在TCP首部加上一个12字节的伪首部。检验和总共计算3部分:TCP首部、TCP数据、TCP伪首部

  • 最大长度:在建立TCP连接的时候,双方约定一个最大的长度(MSS)作为发送的单位,重传的时候也是以这个单位来进行重传。理想的情况下是该长度的数据刚好不被网络层分块。

  • 流量控制:TCP为它的应用程序提供了流量控制服务来避免发送方因为发送速率过快导致接收方缓存溢出数据丢失的问题。说白了流量控制就是让发送方的发送速率不要太快,让接收方来得及接收。流量控制只是适应点对点而采取的措施。双方可通过在TCP报文的“窗口大小”进行设置己端的窗口大小。端对端的流量控制,也解决包乱序问题(数据包格式有SequenceNumber,是数据包的序号seq,ACK用于确认收到,用来解决不丢包的问题)。每一次读取数据之后,回ack报文,报文中会携带当前缓冲区大小,用来告知对方发送的数据不能超过我接收的缓冲区大小。

  • 滑动窗口:我们上面提到的超时重传的机制存在效率低下的问题,发送一个包到发送下一个包要经过一段时间才可以。这就提出了一个滑动窗口的概念:不必等等确认,发送端直接发送数据,在连续收到三个重复确认应答时,重新发生要求的序列号包。已经接收到的数据包放在窗口缓存内,但下一个期望的数据包序列号是最需要的也是最靠近滑动窗口前面但还未收到的,直到收到后窗口才会后移

8. TCP的滑动窗口

端对端的流量控制,也解决包乱序问题(数据包格式有SequenceNumber,是数据包的序号seq,ACK——用于确认收到,用来解决不丢包的问题)。每一次读取数据之后,回ack报文,报文中会携带当前缓冲区大小,用来告知对方发送的数据不能超过我接收的缓冲区大小。

9. TCP黏包问题

原因: TCP 是一个基于字节流的传输服务(UDP 基于报文的),“流” 意味着 TCP 所传输的数据是没有边界的。所以可能会出现两个数据包黏在一起的情况。

解决:

  • 发送定长包。如果每个消息的大小都是一样的,那么在接收对等方只要累计接收数据,直到数据等于一个定长的数值就将它作为一个消息。
  • 包头加上包体长度。包头是定长的 4 个字节,说明了包体的长度。接收对等方先接收包头长度,依据包头长度来接收包体。
  • 在数据包之间设置边界,如添加特殊符号 标记。FTP 协议正是这么做的。但问题在于如果数据正文中也含有 ,则会误判为消息的边界。

10. 简述域名解析过程,本机如何干预域名解析

  • 1)在浏览器中输入www.qq.com域名,操作系统会先检查自己本地的hosts文件是否有这个网址映射关系,如果有,就先调用这个IP地址映射,完成域名解析。

  • 2)如果hosts里没有这个域名的映射,则查找本地DNS解析器缓存,是否有这个网址映射关系,如果有,直接返回,完成域名解析。

  • 3)如果hosts与本地DNS解析器缓存都没有相应的网址映射关系,首先会找TCP/IP参数中设置的首选DNS服务器,在此我们叫它本地DNS服务器,此服务器收到查询时,如果要查询的域名,包含在本地配置区域资源中,则返回解析结果给客户机,完成域名解析,此解析具有权威性。

  • 4)如果要查询的域名,不由本地DNS服务器区域解析,但该服务器已缓存了此网址映射关系,则调用这个IP地址映射,完成域名解析,此解析不具有权威性。

  • 5)如果本地DNS服务器本地区域文件与缓存解析都失效,则根据本地DNS服务器的设置(是否设置转发器)进行查询,如果未用转发模式,本地DNS就把请求发至13台根DNS,根DNS服务器收到请求后会判断这个域名.com是谁来授权管理,并会返回一个负责该顶级域名服务器的一个IP。本地DNS服务器收到IP信息后,将会联系负责.com域的这台服务器。这台负责.com域的服务器收到请求后,如果自己无法解析,它就会找一个管理.com域的下一级DNS服务器地址qq.com给本地DNS服务器。当本地DNS服务器收到这个地址后,就会找qq.com域服务器,重复上面的动作,进行查询,直至找到www.qq.com主机。

  • 6)如果用的是转发模式,此DNS服务器就会把请求转发至上一级DNS服务器,由上一级服务器进行解析,上一级服务器如果不能解析,或找根DNS或把转请求转至上上级,以此循环。不管是本地DNS服务器用是是转发,还是根提示,最后都是把结果返回给本地DNS服务器,由此DNS服务器再返回给客户机。

从客户端到本地DNS服务器是属于递归查询,而DNS服务器之间就是的交互查询就是迭代查询。

10. HTTPS和HTTP的区别

  • HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。

  • HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。

  • 两者的默认端口不一样,HTTP 默认端口号是 80,HTTPS 默认端口号是 443。

  • HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的

11 https的ssl握手连接过程(RSA算法)

HTTPS的安全连接是通过SSL/TLS协议来实现的,在进行TCP三次握手之后,客户端和服务器基于TLS的HTTPS连接过程是这样:

  • 客户端发起连接请求:客户端向服务器发起加密连接请求,并请求建立安全连接。客户端通过向服务器发送ClientHello消息(包含随机数C、客户端TSL版本号、密码套件列表0开始握手过程。
  • 服务器回应并提供数字证书:服务器在收到客户端的ClientHello消息后,回应一个ServerHello消息(包含随机数S、确认TSL版本号,使用的密码套件),并提供服务器的数字证书,然后发送Sever Hello Done表示第二次握手完成。该数字证书会包含了服务器的公钥。
  • 客户端生成密钥:客户端通过自身的信任根证书列表(Trust Store)验证服务器的数字证书的合法性,确保服务器的身份是合法的。若合法客户端生成一个随机的对称密钥(称为Pre-Master Secret),用于加密通信过程中的数据。客户端将这个密钥使用服务器的公钥加密,并发送给服务器。
  • 服务器私钥解密并回Finish:服务器收到客户端发送的加密后的对称密钥,使用自己的私钥进行解密得到这个随机数,之后双方都有三个随机数,双方使用双方协商的加密算法得到对称密钥。并发送Finished消息,表示握手阶段结束。此时,安全通道已经建立,客户端和服务器可以开始通过这个安全通道进行加密通信。

一般情况下,不管 TLS 握手次数如何,都得先经过 TCP 三次握手后才能进行,因为 HTTPS 都是基于 TCP 传输协议实现的,得先建立完可靠的 TCP 连接才能做 TLS 握手的事情。TSL1.2是四次,TSL1.3是两次次(将clientHello与keyshare合并,ServerHello与Finished合并)

12 SSL/TSL的对称加密和非对称加密

SSL/TLS 协议实际上使用了两种加密技术:非对称加密(公钥加密)和对称加密。

  • 非对称加密(公钥加密/私钥解密)在SSL/TLS握手过程中,服务器和客户端使用非对称加密来进行身份验证和密钥交换。服务器拥有一对公钥和私钥。公钥用于加密,私钥用于解密。客户端在连接建立时会向服务器请求其公钥。服务器将公钥发送给客户端,客户端使用服务器的公钥加密生成的随机对称密钥,并将其发送给服务器。只有服务器拥有相应的私钥才能解密这个消息,从而获取客户端生成的对称密钥。
  • 对称加密:一旦握手阶段完成,服务器和客户端就使用协商好的对称密钥进行通信,这个对称密钥是在握手过程中通过非对称加密交换的。对称加密算法比非对称加密算法快得多,因此在通信的实际数据传输过程中,使用对称加密提供更高的性能。

综合而言,SSL/TLS 协议使用非对称加密(公钥加密)来安全地协商生成对称密钥,并通过对称密钥加密通信内容。这样做的好处是结合了非对称加密的安全性和对称加密的性能,使得在安全通信建立和实际数据传输过程中都能得到充分的保护。

12(1) 客户端通验证CA证书的真实性和有效性

  • 证书链验证:客户端收到服务器的证书后,会检查证书的签发者。如果签发者不是根证书,客户端需要根据证书中的签发者信息,向相应的CA请求该中间证书。这个过程会一级一级进行,直到找到根证书。
  • 根证书验证:一旦找到根证书,客户端会使用根证书中的公钥来验证中间证书的签名。如果验证成功,客户端可以信任该中间证书。
  • 证书内容验证:客户端还会验证证书中的其他信息,如证书持有者信息、公钥信息等,以确保证书的完整性和正确性。
  • 数字签名验证:客户端使用CA的公钥对证书中的数字签名进行解密,得到一个摘要值。然后,客户端使用相同的哈希算法对证书中的明文部分进行哈希,得到另一个摘要值。如果这两个摘要值相同,则证书没有被篡改,是真实有效的。

13 非对称加密算法ECDHE

TSL在握手建立对称加密通信的过程中会使用非对称加密算法加密,常见的非对称加密算法由RSA和ECDHE算法,上面在https的ssl握手连接过程(RSA算法)介绍的是以RSA非对称加密的连接过程,

使用 RSA 密钥协商算法的最大问题是不支持前向保密,因为客户端传递随机数(用于生成对称加密密钥的条件之一)给服务端时使用的是公钥加密的,服务端收到到后,会用私钥解密得到随机数。所以一旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS 通讯密文都会被破解。

因此衍生出了更加安全的ECDHE算法:ECDHE

13 一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

HTTP/1.1 中,单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠。

在 HTTP/1.1 存在 Pipelining 技术可以完成这个多个请求同时发送,但是由于浏览器默认关闭,所以可以认为这是不可行的。在 HTTP2 中由于 Multiplexing 特点的存在,多个 HTTP 请求可以在同一个 TCP 连接中并行进行。

那么在 HTTP/1.1 时代,浏览器是如何提高页面加载效率的呢?主要有下面两点:

  • 维持和服务器已经建立的 TCP 连接,在同一连接上顺序处理多个请求。
  • 和服务器建立多个 TCP 连接。

14 输入一个URL会发生什么?

  • 查浏览器缓存,看看有没有已经缓存好的,如果没有则通过调用gethostbyname函数进行DNS域名解析
  • 首先通过DNS进行域名解析:浏览器通过访问DNS服务器完成域名对应的IP地址(如果在一个子网内采用ARP地址解析协议进行ARP查询如果不在一个子网那就需要对默认网关进行DNS查询),(如果无法解析域名,则访问失败)
  • 建立TCP连接:浏览器使用获取到的服务器 IP 地址,通过TCP协议的三次握手建立与服务器的连接。
  • 发起http请求:建立了TCP连接后,浏览器就会向服务器发送一个HTTP请求。这个请求包括了要访问的资源的路径、请求方法(GET、POST等)以及其他可能的请求头信息。
  • 服务器处理请求并反向响应:服务器处理完请求后,会生成一个HTTP响应。这个响应包括了状态码、响应头和响应
  • 浏览器渲染:浏览器收到服务器的HTTP响应后,根据响应的内容类型(Content-Type),开始解析和渲染页面
  • 关闭TCP连接:当页面被完全加载并渲染,浏览器会关闭与服务器的TCP连接

注意,如果使用的是https协议,则会在建立TCP连接后尝试发送http请求包,服务器会返回一个5开头的的重定向消息,告诉我们用的是https,IP没变,但是端口号从80变成443了,好了,四次挥手会后再次tcp连接有额外的操作,使用SSL/TSL协议建立加密通道(见https的ssl连接过程)

因此上述过程涉及到可DNS协议、TCP协议、HTTP、HTTPS协议(ssl协议)、IP协议,同时还可能会用到ARP协议

15 DNS是什么?

DNS(Domain Name System,域名系统),因特网上作为域名和IP地址相互映射的一个分布式数据库,能够使用户更方便的访问互联网,就比如www.baidu.com更容易被人记住,而不是记住它的IP地址

通过主机域名,最终能得到该主机名对应的IP地址的过程叫做域名解析(或主机名解析),

16 DNS的工作原理

DNS是一种应用层协议,使用UDP传输,负责将主机域名转换为IP地址。其工作原理是这样的:

  • 1)当用户输入域名时,浏览器先检查自己的缓存中是否包含这个域名映射的ip地址,有则解析结束。
  • 2)若没命中,则检查操作系统缓存(如Windows的hosts)中有没有解析过的结果,有解析结束。
  • 3)若无命中,则请求本地域名服务器解析(LDNS),命中则把解析结构返回给客户端。
  • 4)若LDNS没有命中就直接跳到根域名服务器请求解析。根域名服务器返回给LDNS一个主域名服务器地址。
  • 5)此时LDNS再发送请求给上一步返回的gTLD( 通用顶级域), 接受请求的gTLD查找并返回这个域名对应的Name Server的地址
  • 6)Name Server根据映射关系表找到目标ip,返回给LDNS
  • 7)LDNS缓存这个域名和对应的ip, 把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束

17 为什么域名解析用UDP协议?

因为UDP协议无连接的更加快,只要一个请求一个应答就好了,也更加适用这种应用场景

18 DNS负载均衡是什么策略?

当一个网站有足够多的用户的时候,假如每次请求的资源都位于同一台机器上面,那么这台机器随时可能会崩掉。处理办法就是用DNS负载均衡技术,它的原理是在DNS服务器中为同一个主机名配置多个IP地址,在应答DNS查询时,DNS服务器对每个查询将以DNS文件中主机记录的IP地址按顺序返回不同的解析结果,将客户端的访问引导到不同的机器上去,使得不同的客户端访问不同的服务器,从而达到负载均衡的目的。例如可以根据每台机器的负载量,该机器离用户地理位置的距离等等

19 DNS查询方式有哪些?

两种,一个是递归解析另一个是迭代解析

  • 递归解析:当局部DNS服务器自己不能回答客户机的DNS查询时,它就需要向其他DNS服务器进行查询。此时有两种方式。局部DNS服务器自己负责向其他DNS服务器进行查询,一般是先向该域名的根域服务器查询,再由根域名服务器一级级向下查询。最后得到的查询结果返回给局部DNS服务器,再由局部DNS服务器返回给客户端,并且将结果缓存本地。

  • 迭代解析:当局部DNS服务器自己不能回答客户机的DNS查询时,局部DNS服务器自己不向其他DNS服务器进行查询,而是把能解析该域名的其他DNS服务器的IP地址返回给客户端,客户端DNS程序再继续向这些DNS服务器进行查询,直到得到查询结果为止。也就是说,迭代解析只是帮你找到相关的服务器而已,而不会帮你去查。

两种解析方式中递归解析将搜素工作交给局部DNS,局部DNS的解析压力增加,迭代解析将结果给客户端,由客户端搜索解析结果,能够环境局部DNS的解析压力。

20 HTTP长连接和短连接的区别

  • 在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。
  • 而从HTTP/1.1起,默认使用长连接,用以保持连接特性。

21 HTTP1.0和HTTP1.1的区别

  • 持久连接:HTTP1.0的连接默认是非持久的,每个请求/响应都需要单独的连接,如果想要使用持久连接,需要在请求头中显式声明。而HTTP/1.1持久连接是默认的
  • 管道化HTTP/1.0不支持管道化,即客户端需要等待上一个请求的响应才能发送下一个请求,HTTP/1.1引入了管道化,可以在一个持久连接上发送多个请求,而无需等待响应。
  • 主机头:HTTP 1.1增加host字段,使得一个服务器上可以托管多个域名(虚拟主机),通过主机头字段来区分不同的域名。
  • 缓存控制HTTP/1.1: 引入了更灵活的缓存控制,包括 Cache-Control 头,允许更细粒度的控制缓存行为,HTTP/1.0: 缓存控制较为简单,通常依赖于 Expires 头的定期时间

但 HTTP/1.1 还是有性能瓶颈:

  • 请求 / 响应头部(Header)未经压缩就发送,首部信息越多延迟越大。只能压缩 Body 的部分;
  • 发送冗长的首部。每次互相发送相同的首部造成的浪费较多;
  • 服务器是按请求的顺序响应的,如果服务器响应慢,会招致客户端一直请求不到数据,也就是队头阻塞;
  • 没有请求优先级控制;
  • 请求只能从客户端开始,服务器只能被动响应。

22 HTTP/2比HTTP/1.1相比的区别

HTTP/2 协议是基于 HTTPS 的,所以 HTTP/2 的安全性也是有保障的。相比与HTTP/1.1,有性能上的改进

  • 头部压缩:HTTP/2 会压缩头(Header)如果你同时发出多个请求,他们的头是一样的或是相似的,那么,协议会帮你消除重复的部分。
  • 二进制格式:HTTP/2 不再像 HTTP/1.1 里的纯文本形式的报文,而是全面采用了二进制格式,头信息和数据体都是二进制,并且统称为帧(frame):头信息帧(Headers Frame)和数据帧(Data Frame)
  • 并发传输:我们都知道 HTTP/1.1 的实现是基于请求-响应模型的。同一个连接中,HTTP 完成一个事务(请求与响应),才能处理下一个事务,也就是说在发出请求等待响应的过程中,是没办法做其他事情的,如果响应迟迟不来,那么后续的请求是无法发送的,也造成了队头阻塞的问题。而HTTP/2引出了stream的概念, 一个 TCP 连接包含多个 Stream,Stream 里可以包含 1 个或多个 Message,Message 有多个Fram,Frame对应 HTTP/1 中的请求或响应,由 HTTP 头部和包体构成,不过这里是二进制的格式而不是文本。针对不同的 HTTP 请求用独一无二的 Stream ID 来区分,接收端可以通过 Stream ID 有序组装成 HTTP 消息,不同 Stream 的帧是可以乱序发送的,因此可以并发不同的 Stream ,也就是 HTTP/2 可以并行交错地发送请求和响应。
  • 服务器推送:HTTP/2 还在一定程度上改善了传统的「请求 - 应答」工作模式,服务端不再是被动地响应,可以主动向客户端发送消息。客户端和服务器双方都可以建立 Stream, Stream ID 也是有区别的,客户端建立的 Stream 必须是奇数号,而服务器建立的 Stream 必须是偶数号。

HTTP/2 有什么缺陷? HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,因此对于HTTP2来说仍然是由TCP造成的队头阻塞问题,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应用层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题

22 HHTP/3

上面提到了HTTP/2,HTTP/2通过头部压缩、二进制格式、并发传输stream流、服务器推送等新特性大大提升了HTTP/1.1的性能。但还是存储缺陷:

  • 因为是依赖于TCP实现的,还是有队头阻塞问题(即一个之前包未过来,那么当前TCP滑动窗口就不能把这些数据提交到上一层)
  • TCP与TLS的握手延迟,还是要在建立TCP后建立TLS(HTTP/2中默认支持使用了是TLS1.2版本)
  • 网络迁移需要重新连接,一个 TCP 连接是由四元组(源 IP 地址,源端口,目标 IP 地址,目标端口)确定的,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WiFi。

而HTTP/3就克服了这些点,并且继承了了HTTP/2的头部压缩、二进制格式传输、并发传输stream流等特性。

HTTP/3 不仅仅只是简单将传输协议替换成了 UDP,还基于 UDP 协议在「应用层」实现了 QUIC 协议,它具有类似** TCP 的连接管理、拥塞窗口、流量控制的网络特性**,相当于将不可靠传输的 UDP 协议变成“可靠”的了,所以不用担心数据包丢失的问题,同时利用QUIC特点克服上述HTTP/2的三个困难:

  • 无队头阻塞;不是使用TCP,而是UDP。因此无队头阻塞问题。
  • 更快的连接建立;使用TLS1.3
  • 连接迁移;不在使用四元组标识一个连接,而是通过连接ID来标记通信的两个端点

22 为什么服务器会有缓存这一项功能?如何实现的?

原因

  • 缓解服务器压力;
  • 降低客户端获取资源的延迟:缓存通常位于内存中,读取缓存的速度更快。并且缓存服务器在地理位置上也有可能比源服务器来得近,例如浏览器缓存。

实现方法

  • 让代理服务器进行缓存;
  • 让客户端浏览器进行缓存

23 Cookie是什么

HTTP协议是无状态的,然后在HTTP/1.1引入了Cookie来保存状态,Cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它的作用其实就是让服务器知道客户端是谁。比如你每刷新一次网页,就要重新输入一次账号密码进行登录。这显然是让人无法接受的,那么cookie 的作用就好比服务器给你贴个标签,然后你每次向服务器再发请求时,服务器就能够通过cookie 认出你。

24 Cookie有什么用途?

  • 会话状态管理(如用户登录状态、购物车、游戏分数或其它需要记录的信息)
  • 个性化设置(如用户自定义设置、主题等)
  • 浏览器行为跟踪(如跟踪分析用户行为等

25 session是什么

Session也是记录用户状态的,但与Cookie把用户状态存储在用户浏览器不同,Session是将用户状态存储到服务端。两者配合,即浏览器的Cookie会有Session ID,后续将Cookie发送给服务器后,会依据这个Session Id找到相应的用户状态

使用 Session 维护用户登录状态的过程如下:

  • 用户进行登录时,用户提交包含用户名和密码的表单,放入 HTTP 请求报文中;
  • 服务器验证该用户名和密码,如果正确则把用户状态存储到 Redis 中,它在 Redis 中的 Key 称为 Session ID;
  • 服务器返回的响应报文的Set-Cookie 首部字段包含了这个** Session ID**,客户端收到响应报文之后将该Cooki值Session ID 存入浏览器中;
  • 客户端之后对同一个服务器进行请求时会包含该 Cookie 值,服务器收到之后提取出 Session ID,从 Redis 中取出用户信息,继续之前的业务操作

注意:Session ID 的安全性问题,不能让它被恶意攻击者轻易获取,那么就不能产生一个容易被猜到的 Session ID 值。此外,还需要经常重新生成 Session ID。在对安全性要求极高的场景下,例如转账等操作,除了使用 Session 管理用户状态之外,还需要对用户进行重新验证,比如重新输入密码,或者使用短信验证码等方式。

Session 可以存储在服务器上的文件、数据库或者内存中。也可以将 Session 存储在 Redis 这种内存型数据库中,效率会更高。

如果客户端的浏览器禁用了Cookie,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,URL后面都会被附加上一个诸如sid=xxxxx这样的参数,服务端据此来识别用户

26 SQL注入攻击了解吗

攻击者在HTTP请求中注入恶意的SQL代码,服务器使用参数构建数据库SQL命令时,恶意SQL被一起构造,并在数据库中执行.比如用户登录,输入用户名 lianggzone,密码 ''or 1=1 ,如果此时使用参数构造的方式,就会出现 select * from user where name = 'lianggzone' and password = '' or 1=1 不管用户名和密码是什么内容,上述的查询语句中1=1总是成立,因此总是能够查询全表内容。

如何防止:

  • 服务端进行有效性检验
  • 限制字符串,过滤一些SQL需要的的特殊字符

27 ARP协议

IP是在网络层上的只是用于标识网络设备的虚拟地址,只是一个逻辑地址,而一个数据要发到哪里还需要经过链路层,也就是要知道设备的物理地址也叫Mac地址,Mac地址用于标识网络中的物理设备。MAC 地址用于在局域网络(LAN)中直接交换数据帧,确保它们被正确地从一个物理设备传递到另一个。

ARP协议是知道主机ip地址但不知道Mac地址时用于在本地网络中找到目标设备的硬件MAC地址的协议,从而使数据帧正确发送到目标

ARP 的基本工作流程如下:

  • 1.ARP请求(ARP Request):当一台设备需要发送数据帧到网络中的另一台设备时,它首先检查目标设备的IP地址是否在其本地子网内。如果是,它会使用 ARP 发送一个广播请求,询问目标设备的MAC地址,(不在同一子网内会使用ARP的替代品Proxy ARP或Gratuitous ARP)
  • 2.ARP应答(ARP Reply):如果目标设备在本地网络中,并且处于活动状态,它将向发送ARP请求的设备发送一个单播 ARP 应答,包含自己的MAC地址。
  • ARP缓存(ARP Cache):发送ARP请求的设备会在一个称为 ARP 缓存表的本地缓存中存储已解析的IP地址和相应的MAC地址,以便将来直接使用,而不必发出新的ARP请求。

28 ARP欺骗

ARP 是一个简单而有效的协议,但也容易受到欺骗攻击, ARP 欺骗(ARP Spoofing)攻击是指其中攻击者发送虚假的 ARP 应答来欺骗网络设备将数据发送到错误的目标。为了增加安全性,可以使用工具和技术来检测和防范 ARP 欺骗攻击。

29 RARP是什么(一般对自己使用,如开机不知道自己的ip地址)

RARP与ARP相反。 RARP是知道主机硬件Mac地址但不知道ip地址,因此使用RARP来得到主机IP地址的的协议,也叫反向地址转换协议。

  • 1.RARP请求(ARP Request):使用 RARP 发送一个广播请求,询问设备的IP地址,
  • 2.ARP应答(ARP Reply):RARP 服务器收到请求后,会查找发送请求计算机的 MAC 地址,并将其对应的 IP 地址返回给计算机。
  • ARP缓存(ARP Cache):收到 RARP 响应后,计算机将获取到的 IP 地址配置到其网络接口

30 OSI七层模型及作用

31 HTTP中缓存的私有和共有字段?知道吗?

private 指令规定了将资源作为私有缓存,只能被单独用户使用,一般存储在用户浏览器中。

1
Cache-Control: private
public 指令规定了将资源作为公共缓存,可以被多个用户使用,一般存储在代理服务器中。
1
Cache-Control: public

32 DDos攻击了解吗?

客户端向服务端发送请求链接数据包,服务端向客户端发送确认数据包,客户端不向服务端发送确认数据包,服务器一直等待来自客户端的确认 没有彻底根治的办法,除非不使用TCP

DDos 预防: 1)限制同时打开SYN半链接的数目 2)缩短SYN半链接的Time out 时间 3)关闭不必要的服务

33 MTU和MSS分别是什么?

  • MTU:maximum transmission unit,最大传输单元,是链路层的概念,示在一个网络通信链路上可以传输的最大数据包的大小。

  • MSS:是传输控制协议(TCP)中的概念,表示在一个 TCP 报文段中的数据字段的最大大小,一般由发送端向对端TCP通知对端在每个分节中能发送的最大TCP数据。MSS值为MTU值减去IPv4 Header(20 Byte)和TCP header(20 Byte)得到

在实际网络通信中,TCP 会根据网络链路的 MTU 来动态调整 MSS 的大小,以确保在不发生分片的情况下进行数据传输

32 Http的缓存策略有哪些

HTTP协议的缓存策略是浏览器每次发起请求时,先在本地缓存中查找结果以及缓存标识,根据缓存标识来判断是否使用本地缓存。如果缓存有效,则使用本地缓存,否则,则向服务器发起请求并携带缓存标识。HTTP协议的缓存策略分两种:强制缓存和协商缓存,而强制缓存优先级大于协商缓存。

  • 强制缓存:服务器告诉浏览器一个缓存时间,在缓存时间内,下次请求,直接用缓存,不在时间内,执行比较缓存策略。
  • 协商缓存:让客户端与服务器之间能实现缓存文件是否更新的验证、提升缓存的复用率,将缓存信息中的Etag和Last-Modified通过请求发送给服务器,由服务器校验。如果文件没有改变,那么直接返回304状态,继续使用浏览器缓存。

34 HTTP中有个缓存机制,但如何保证缓存是最新的呢?(缓存过期机制)

在 HTTP 引入了缓存机制,在保证缓存的同时,还确保了缓存的内容是最新的,常用的策略包括使用过期机制和验证机制。这两种机制都通过 HTTP 头部来实现。

  • 强制缓存:HTTP 响应头部中的Cache-Contro(http1.1)l 和 Expires(http1.0) 字段用于控制缓存的过期时间。Cache-Control 中的 max-age 指定了资源在被认为陈旧之前可以被缓存的时间(以秒为单位)。Expires 字段指定了资源的过期日期,是一个具体的日期和时间。(如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires 。) -当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
    • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
    • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control
      1
      2
      Cache-Control: max-age=31536000
      Expires: Tue, 01 Jan 2024 00:00:00 GMT
  • 协商缓存:协商缓存就是客户端与服务器协商之后,通过协商结果来判断是否使用本地缓存。验证机制使用了一些条件标头,如响应头 Last-Modified(资源最后修改的时间)ETag(资源的唯一标识),以及相应的请求头If-Modified-SinceIf-None-Match
    • 第一种:客户端发起请求,用请求头if-Modified-Since带上前段时间服务器响应的last-modified响应头的值,服务器收到请求后 If-Modified-Since的值与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。
    • 第二种:当客户端向服务器发起请求时,会将之前响应头Etag 的值设置在请求头的 If-None-Match中。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。

第一种实现方式是基于时间实现的,第二种实现方式是基于一个唯一标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。

协商缓存这两个字段都需要配合强制缓存中 Cache-Control 字段来使用,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。

35 网络层常见协议

  • ip:IP协议不但定义了数据传输时的基本单元和格式,还定义了数据报的递交方法和路由选择
  • ICMP:ICMP就是一个“错误侦测与回报机制”,其目的就是让我们能够检测网路的连线状况﹐也能确保连线的准确性,是ping和traceroute的工作协议

35 在进行UDP编程的时候,一次发送多少bytes好?

以太网(Ethernet)数据帧的长度必须在46-1500字节之间,这是由以太网的物理特性决定的.这个1500字节被称为链路层的MTU(最大传输单元)

所以,事实上,这个1500字节就是网络层IP数据报的长度限制。因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节.而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的.又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节.这个1472字节就是我们可以使用的字节数。

所以,事实上,这个1500字节就是网络层IP数据报的长度限制。因为IP数据报的首部为20字节,所以IP数据报的数据区长度最大为1480字节.而这个1480字节就是用来放TCP传来的TCP报文段或UDP传来的UDP数据报的.又因为UDP数据报的首部8字节,所以UDP数据报的数据区最大长度为1472字节.这个1472字节就是我们可以使用的字节数。

因此,在普通的局域网环境下,我建议将UDP的数据控制在1472字节以下为好

36 常见的HTTP状态码有哪些?

状态码 类别 含义
1XX Informational(信息性状态码) 接收的请求正在处理
2XX Success(成功状态码) 请求正常处理完毕
3XX Redirection(重定向状态码) 需要进行附加操作以完成请求
4XX Client Error(客户端错误状态码) 服务器无法处理请求
5XX Server Error(服务器错误状态码) 服务器处理请求出
1xx 信息
  • 100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。
2xx 成功
  • 200 OK
  • 204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。
  • 206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。
3xx 重定向
  • 301 Moved Permanently :永久性重定向
  • 302 Found :临时性重定向
  • 303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。
  • 304 Not Modified :如果请求报文首部包含一些条件,例如:If-Match,If-Modified-Since,If-None-Match,If-Range,If-Unmodified-Since,如果不满足条件,则服务器会返回 304 状态码。
  • 307 Temporary Redirect :临时重定向,与 302 的含义类似,但是 307 要求浏览器不会把重定向请求的 POST 方法改成 GET 方法。
4xx 客户端错误
  • 400 Bad Request :请求报文中存在语法错误。
  • 401 Unauthorized :该状态码表示发送的请求需要有认证信息(BASIC 认证、DIGEST 认证)。如果之前已进行过一次请求,则表示用户认证失败。
  • 403 Forbidden :请求被拒绝。
  • 404 Not Found
5xx 服务器错误
  • 500 Internal Server Error :服务器正在执行请求时发生错误。
  • 503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

37 服务器出现大量close_wait的连接的危害和原因是什么?有什么解决方法?

  • 资源占用:每个处于CLOSE_WAIT状态的连接都会占用一个文件描述符。在Linux系统中,一个进程能够同时打开的文件描述符数量是有限的。当CLOSE_WAIT状态的连接数量过多时,可能会达到文件描述符的上限,导致服务端进程无法再创建新的socket来响应新的请求,从而使服务变得不可用。
  • 性能下降:大量的CLOSE_WAIT状态连接会占用系统非换页内存,并可能导致网络可用连接减少。特别是在有连接池的情况下(比如HttpRequest),可能会耗尽连接池的网络连接数,导致无法建立新的网络连接,从而影响网络性能。

close_wait状态是在TCP四次挥手的时候收到客户端的FIN但是没有发送自己的FIN时出现的,服务器出现大量close_wait状态的原因有两种:

  • 服务器内部业务处理占用了过多时间,都没能处理完业务(如数据库IO任务);或者还有数据需要发送;或者服务器的业务逻辑有问题,没有执行close()方法
  • 服务器的父进程派生出子进程,子进程继承了socket,收到FIN的时候子进程处理但父进程没有处理该信号,导致socket的引用不为0无法回收

处理方法:

  • 停止应用程序
  • 修改程序里的bug
  • 调整连接超时时间:在操作系统中增加或减少连接超时时间,以便在连接关闭后更快地从连接表中删除。可以通过调整操作系统的网络参数或配置文件来实现。
  • 增加操作系统的连接文件描述符大小:增加操作系统的连接表大小可以容纳更多的连接。可以通过修改操作系统的网络参数或配置文件来实现。

38 http的请求报文和响应报文格式

  • 请求报文:uri格式:protocol://[username:password@]hostname[:post][/path][[?query][#fragment]

    1
    2
    3
    4
    Method URI HTTP/version\r\n(请求行)
    请求头\r\n
    \r\n(空行)
    请求消息\r\n

  • 响应报文格式

    1
    2
    3
    4
    HTTP/version 状态码 状态描述\r\n
    响应头\r\n
    \r\n(空行)
    响应消息体\r\n

39 http中大文件传输你是怎么处理的

我是使用了分片传输的技术来实现大文件的传输,在http中提供了Transfer-Encoding: chunked的头部支持我们对文件进行分片传输,具体操作是这样的:

  • 第一次服务器向客户端发送不包含相应消息体的响应包,改薄必须有Transfer-Encoding: chunked头部信息
  • 之后依据你设定每次传输多大的消息体,直接传输这些消息即可,不必再发送含义状态行、响应头部和空行。
  • 最后发送完毕后,发送消息体为空的信息即可

40 为什么每次建立 TCP 连接时,初始化的序列号是随机的呢都要求不一样呢?

主要是防止历史报文被下一个相同四元组的连接接收(主要方面)。,假设每次建立连接,客户端和服务端的初始化序列号都是从 0 开始:

  • 客户端和服务端建立一个 TCP 连接,在客户端发送数据包被网络阻塞了,然后超时重传了这个数据包,而此时服务端设备断电重启了,之前与客户端建立的连接就消失了,于是在收到客户端的数据包的时候就会发送 RST 报文。
  • 紧接着,客户端又与服务端建立了与上一个连接相同四元组的连接;
  • 在新连接建立完成后,上一个连接中被网络阻塞的数据包正好抵达了服务端,刚好该数据包的序列号正好是在服务端的接收窗口内,所以该数据包会被服务端正常接收,就会造成数据错乱。

可以看到,如果每次建立连接,客户端和服务端的初始化序列号都是一样的话,很容易出现历史报文被下一个相同四元组的连接接收的问题。

41 TCP的半连接队列和全连接队列知道吗?

  • 半连接队列:也称 SYN 队列,只要客户端的连接请求被服务器listen到就会发在半连接队列(由哈希表实现)
  • 全连接队列:也称 accept 队列,完成TCP三层握手之后就会放在全连接队列,等待服务器的accept提取(由链表实现)

那半连接队列遇到SYN攻击直接被打满了,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。怎么防止?

  • 方式一:增大半连接队列,可以通过设置增大。
  • 方式二:减少 SYN+ACK 重传次数,当服务端受到 SYN 攻击时,就会有大量处于 SYN_REVC 状态的 TCP 连接,处于这个状态的 TCP 会重传 SYN+ACK ,当重传超过次数达到上限后,就会断开连接。那么针对 SYN 攻击的场景,我们可以减少 SYN-ACK 的重传次数,以加快处于 SYN_REVC 状态的 TCP 连接断开。

42 如果已经建立了连接,但是客户端突然出现故障了怎么办

客户端出现故障指的是客户端的主机发生了宕机,或者断电的场景。发生这种情况的时候,如果服务端一直不会发送数据给客户端,那么服务端是永远无法感知到客户端宕机这个事件的,也就是服务端的 TCP 连接将一直处于 ESTABLISH 状态,占用着系统资源。

为了避免这种情况,TCP 搞了个保活机制。这个机制的原理是这样的:

定义一个时间段,在这个时间段内,如果没有任何连接相关的活动,TCP 保活机制会开始作用,每隔一个时间间隔,发送一个探测报文,该探测报文包含的数据非常少,如果连续几个探测报文都没有得到响应,则认为当前的 TCP 连接已经死亡,系统内核将错误信息通知给上层应用程序。

1
2
3
net.ipv4.tcp_keepalive_time=7200
net.ipv4.tcp_keepalive_intvl=75
net.ipv4.tcp_keepalive_probes=9
  • tcp_keepalive_time=7200:表示保活时间是 7200 秒(2小时),也就 2 小时内如果没有任何连接相关的活动,则会启动保活机制
  • tcp_keepalive_intvl=75:表示每次检测间隔 75 秒;
  • tcp_keepalive_probes=9:表示检测 9 次无响应,认为对方是不可达的,从而中断本次的连接。

也就是说在 Linux 系统中,最少需要经过 2 小时 11 分 15 秒才可以发现一个「死亡」连接。

43 如果已经建立了连接,但是服务端的进程崩溃会发生什么?

TCP 的连接信息是由内核维护的,所以当服务端的进程崩溃后,内核需要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不需要进程的参与,所以即使服务端的进程退出了,还是能与客户端完成 TCP 四次挥手的过程。

44 客户端调用 close 了,连接的断开的流程是什么

  • 客户端调用 close,表明客户端没有数据需要发送了,则此时会向服务端发送 FIN 报文,进入 FIN_WAIT_1 状态;
  • 服务端接收到了 FIN 报文,TCP 协议栈会为 FIN 包插入一个文件结束符 EOF 到接收缓冲区中,应用程序可以通过 read 调用来感知这个 FIN 包。这个 EOF 会被放在已排队等候的其他已接收的数据之后,这就意味着服务端需要处理这种异常情况,因为 EOF 表示在该连接上再无额外数据到达。此时,服务端进入 CLOSE_WAIT 状态
  • 接着,当处理完数据后,自然就会读到 EOF,于是也调用 close 关闭它的套接字,这会使得服务端发出一个 FIN 包,之后处于 LAST_ACK 状态;
  • 客户端接收到服务端的 FIN 包,并发送 ACK 确认包给服务端,此时客户端将进入 TIME_WAIT 状态;
  • 服务端收到 ACK 确认包后,就进入了最后的 CLOSE 状态;
  • 客户端经过 2MSL 时间之后,也进入 CLOSE 状态;

45 没有 accept,能建立 TCP 连接吗?

可以,accpet只是从全连接队列中提取出已完成三次握手的连接,在accpet返回前就已经建立号socket连接了。

46 已建立连接的SYN,再次收到SYN报文会怎么样?

  • SYN内端口号与历史连接相同:首先即使正常建立了连接,服务器还是会人为这是来自客户端的一个新连接,因此会正常会一个ACK报文,此时这个ACK被成为Challenge ACK,但此时客户端发现这个ack报文的序列号不是自己想要的,于是就会回 RST 报文,服务端收到后,就会释放掉该连接

  • SYN里的端口号与历史连接不同:正常建立一个新的连接。

47 四次挥手收到乱序的FIN包会如何,(即服务端的数据包因阻塞落后于FIN包的到达,此时会怎样)?

首先FIN包乱序,他不会被处理,而是加入到乱序队列(TCP的滑动窗口),因此此时客户端的 TCP 连接并不会从 FIN_WAIT_2状态转换到 TIME_WAIT状态,仍然可以处理哪些滞后到达的数据包

等再次收到前面被网络延迟的数据包时,会判断乱序队列有没有数据,然后会检测乱序队列中是否有可用的数据,如果能在乱序队列中找到与当前报文的序列号保持的顺序的报文,就会看该报文是否有 FIN 标志,如果发现有 FIN 标志,这时才会进入 TIME_WAIT 状态。

48 在 TIME_WAIT 状态的 TCP 连接,收到 SYN 后会发生什么?

SYN代表连接请求,可以分两种情况

  • 如果收到的SYN包的序列号比服务器期望的要大,那么此时立马重新建立连接,服务器的连接状态处于SYN_RECV
  • 如果收到的SYN包的序列号比服务器期望的要小,,就会再回复一个第四次挥手的 ACK 报文,客户端收到后,发现并不是自己期望收到确认号(ack num),就回 RST 报文给服务端。

49 TCP连接没有打开keepalive保活机制,没有数据交互,现在一端断电金额一端进程crash掉的区别?

  • 主机崩溃(断电):客户端主机崩溃了,服务端是无法感知到的,在加上服务端没有开启 TCP keepalive,又没有数据交互的情况下,服务端的 TCP 连接将会一直处于 ESTABLISHED 连接状态,直到服务端重启进程。
  • 进程崩溃:TCP 的连接信息是由内核维护的,所以当服务端的进程崩溃后,内核需要回收该进程的所有 TCP 连接资源,于是内核会发送第一次挥手 FIN 报文,后续的挥手过程也都是在内核完成,并不需要进程的参与,所以即使服务端的进程退出了,还是能与客户端完成 TCP四次挥手的过程。

那由数据交互的情况主机奔溃又又什么反应? - 客户端主机宕机,又迅速重启在客户端主机宕机后,服务端向客户端发送的报文会得不到任何的响应,在一定时长后,服务端就会触发超时重传机制,重传未得到响应的报文。服务端重传报文的过程中,客户端主机重启完成后,客户端的内核就会接收重传的报文,然后根据报文的信息传递给对应的进程: - 如果客户端主机上没有进程绑定该 TCP 报文的目标端口号,那么客户端内核就会回复 RST 报文,重置该 TCP 连接; - 如果客户端主机上有进程绑定该 TCP 报文的目标端口号,由于客户端主机重启后,之前的 TCP 连接的数据结构已经丢失了,客户端内核里协议栈会发现找不到该 TCP 连接的 socket 结构体,于是就会回复 RST 报文,重置该 TCP 连接。 - 所以,只要有一方重启完成后,收到之前 TCP 连接的报文,都会回复 RST 报文,以断开连接。 - 客户端主机宕机,一直没有重启:这种情况,服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了,于是服务端的 TCP 连接就会断开。

50 TCP Keepalive 和 HTTP Keep-Alive 是一个东西吗?

不是一个东西。

  • HTTP 的 Keep-Alive,是由应用层(用户态) 实现的,称为 HTTP 长连接;
  • TCP 的 Keepalive,是由 TCP 层(内核态) 实现的,称为 TCP 保活机制

51 分布式请求的总体流程

当一条请求打在集群上时,其处理过程通常涉及多个组件和步骤,以确保请求能够被正确处理和响应。以下是根据搜索结果总结的集群处理请求的一般过程:

  • 客户端请求:客户端向集群中的一个节点发送请求,这个节点可能是负载均衡器、代理服务器或直接是集群中的一个服务实例。
  • 负载均衡:如果请求首先到达负载均衡器,它将根据配置的策略(如轮询、最少连接等)将请求分发到集群中的一个后端服务实例。
  • 服务发现:在微服务架构中,客户端可能需要通过服务发现机制来找到可用的服务实例。这通常涉及到查询服务注册中心,如Zookeeper或Nacos,以获取服务实例的地址信息。
  • 请求路由:一旦客户端知道了可用的服务实例,它将向其中一个实例发送请求。如果请求被打到一个不是负责处理该请求的节点,该节点可能会根据路由规则将请求转发到正确的节点。
  • 请求处理:当请求到达负责处理它的服务实例后,该实例将执行必要的业务逻辑处理请求。这可能包括查询数据库、执行计算、调用其他服务等操作。
  • 数据一致性:在分布式系统中,保持数据一致性是非常重要的。
  • 响应返回:处理完请求后,服务实例将生成响应并返回给客户端。如果请求经过了负载均衡器或代理服务器,响应将按照相反的路径返回。
  • 异步重试:如果请求处理失败,客户端可能会进行异步重试,通过切换到一个不同的服务节点来重新发送请求,以提高系统的可用性。

这个过程可能会根据具体的集群架构、使用的技术栈和配置有所不同,但总体上,这些步骤提供了一个分布式集群处理请求的概览。

52 说说负载均衡算法

常见的负载均衡算法包括轮询法、随机法、源地址哈希法、加权轮询法、加权随机法

  • 轮询(Round Robin)法:将请求按顺序轮流分配到后台服务器上,均衡的对待每一台服务器,而不关心服务器实际的连接数和当前的系统负载
    • 轮询法适用于机器性能相同的服务,一旦某台机器性能不好,极有可能产生木桶效应,性能差的机器扛不住更多的流量。
  • 随机法:通过系统随机函数,根据后台服务器列表的大小值来随机选取其中一台进行访问
  • 随机轮询法:所谓随机轮询,就是将随机法和轮询法结合起来,在轮询节点时,随机选择一个节点作为开始位置index,此后每次选择下一个节点来处理请求,即(index+1)%size
  • 源地址哈希法(一致性哈希):根据服务消费者请求客户端的IP地址,通过哈希函数计算得到一个哈希值,将此哈希值和服务器列表的大小进行取模运算,得到的结果便是要访问的服务器地址的序号。采用源地址哈希法进行负载均衡,相同的IP客户端,如果服务器列表不变,将映射到同一个后台服务器进行访问
  • 加权轮询(Weight Round Robin)法:配置高、负载低的机器分配更高的权重,使其能处理更多的请求,而配置低、负载高的机器,则给其分配较低的权重,降低其系统负载。
    • 比如三台机器(a,b,c)=(1,2,5),那么C机器处理的请求占比高,但容易导致请求集中在C
    • 为了避免这种效果,Nginx的加权轮询算法是这样做的:
      • 每个服务器都有两个权重变量:weight配置文件中指定的该服务器的权重,这个值是固定不变的;current_weight,服务器目前的权重。一开始为0,之后会动态调整。
      • 每次当请求到来,选取服务器时,会遍历数组中所有服务器。对于每个服务器,让它的current_weight增加它的weight;同时累加所有服务器的weight,并保存为total。
      • 遍历完所有服务器之后,如果该服务器的current_weight是最大的,就选择这个服务器处理本次请求。最后把该服务器的current_weight减去total。

53 秒杀系统

秒杀系统设计是一个涉及高并发、低延迟和数据一致性的复杂过程。系统设计原则包括高并发:系统需要能够处理大量用户的请求。低延迟,响应时间要快,避免用户长时间等待。数据一致性:保证商品库存等数据的准确性,防止超卖或少卖。限流:防止恶意攻击或滥用系统。

技术实现方案:

  • 前端限流:通过前端的计时器和按钮状态控制,避免用户连续点击发送大量请求。
  • 后端限流:使用Redis的原子操作作为计数器,确保同一时间段内的请求不超过限制。
  • 异步处理:采用消息队列(如RabbitMQ或Kafka)进行异步处理,缓解直接数据库压力。
  • 库存预减:在Redis中保存商品库存,减少对数据库的直接访问。
  • 数据库优化:采用乐观锁确保数据更新安全,使用缓存减少数据库负载,并对数据库进行读写分离。

  • 系统架构设计:
    • 系统可以分为前端、负载均衡层、服务层和数据库层。
      • 负载均衡层通过Nginx等工具将请求分发到不同的服务器。
      • 服务层处理具体的业务逻辑,如库存检查、订单处理等。
      • 数据库层负责数据的持久化和查询。

通过上述步骤,可以设计出一个高效、稳定的秒杀系统,能够在高并发环境下保持良好的性能和数据一致性。

54