【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关

在学习的时候找到几个十分好的工程和个人博客,先码一下,内容都摘自其中,有些重难点做了补充!
才鲸 / 嵌入式软件笔试题汇总
嵌入式与Linux那些事
阿秀的学习笔记
小林coding
百问网linux
嵌入式软件面试合集
2022年春招实习十四面(嵌入式面经)

文章目录

  • 一、TCP/UDP
    • 1.1 区别和优缺点
      • 1.1.1 区别
      • 1.1.2 优缺点
    • 1.2 TCP怎么保证可靠性?
    • 1.3 TCP的建立连接和断开连接的过程
      • 1.3.1 TCP建立连接
        • 1.3.1.1 三次握手过程
        • 1.3.1.2 为什么是三次握手?
        • 1.3.1.3 为什么每次建立 TCP 连接时,初始化的序列号都要求不一样呢?
        • 1.3.1.4 初始序列号 ISN 是如何随机产生的?
        • 1.3.1.5 什么是 SYN 攻击?如何避免 SYN 攻击?
      • 1.3.2 TCP断开连接
        • 1.3.2.1 四次挥手过程
        • 1.3.2.2 为什么挥手需要四次?
        • 1.3.2.3 为什么 TIME_WAIT 等待的时间是 2MSL?
        • 1.3.2.4 为什么需要 TIME_WAIT 状态?
        • 1.3.2.5 TIME_WAIT 过多有什么危害?
    • 1.3 ISO/OSI模型、TCP/IP协议和模型
      • 1.3.1 OSI七层网络和TCPIP网络模型区别
  • 二、HTTP
    • 2.1 HTTP概念
    • 2.2 GET 与 POST
      • 2.2.1 GET 和 POST 有什么区别?
      • 2.2.2 GET 和 POST 方法都是安全和幂等的吗?
    • 2.3 HTTP 缓存技术
      • 2.3.1 HTTP 缓存有哪些实现方式?
      • 2.3.2 什么是强制缓存?
      • 2.3.3 什么是协商缓存?
    • 2.4 HTTP 特性(HTTP/1.1 )
      • 2.4.1 HTTP/1.1 的优点有哪些?
      • 2.4.2 HTTP/1.1 的缺点有哪些?
      • 2.4.3 HTTP/1.1 的性能如何?
    • 2.5 HTTP 与 HTTPS
      • 2.5.1 HTTP 与 HTTPS 有哪些区别?
      • 2.5.2 HTTPS 解决了 HTTP 的哪些问题?
      • 2.5.3 HTTPS 是如何建立连接的?其间交互了什么?
      • 2.5.4 HTTPS 的应用数据是如何保证完整性的?
      • 2.5.5 HTTPS 一定安全可靠吗?
  • 三、网络编程
    • 3.1 客户端和服务器端相关函数
      • 3.1.1 基于TCP
      • 3.1.2 基于UDP
      • 3.1.3 TCP和UDP中客户端和服务器端使用的函数差异
    • 3.2 Socket编程的send() recv() accept() socket()函数
    • 3.3 网络编程中长链接和短链接

一、TCP/UDP

1.1 区别和优缺点

1.1.1 区别

TCP(Transmission Control Protocol)和UDP(User Datagram Protocol)是两种网络传输协议,它们在数据传输时有以下区别:

  1. 连接方式不同:TCP是面向连接的协议,传输数据之前需要先建立连接,而UDP是无连接的协议,数据传输可以直接发送,不需要先建立连接。
  2. 可靠性不同:TCP是可靠的协议,它通过数据确认、重传等机制保证数据的可靠传输。而UDP是不可靠的协议,它并不保证数据的可靠传输,数据包可能会丢失或者乱序。
  3. 传输效率不同:由于TCP需要建立连接、确认数据、重传等机制,所以传输效率相对较低;而UDP没有这些机制,传输效率相对较高。
  4. 数据大小不同:TCP传输的数据大小没有限制,可以传输任意大小的数据;而UDP传输的数据大小有限制,每个数据包的大小不能超过64KB。
  5. 适用场景不同:TCP适合传输一些重要的数据,例如文件、邮件等,因为它可以保证数据的可靠传输;而UDP适合传输一些时间敏感、实时性要求较高的数据,例如视频、音频等,因为它可以提高传输效率,减少延迟。

1.1.2 优缺点

TCP的优点:

  1. 可靠性高:TCP采用数据确认、重传等机制,保证数据的可靠传输,数据不容易丢失或损坏。
  2. 顺序性好:TCP保证数据顺序传输,数据不会乱序。
  3. 流量控制:TCP可以根据网络情况进行流量控制,避免过多的数据流入,导致网络拥塞。
  4. 适合传输大量数据:TCP可以传输任意大小的数据,适合传输文件、邮件等大量数据。

TCP的缺点:

  1. 连接建立慢:TCP需要进行三次握手建立连接,连接建立的时间相对较长。
  2. 传输效率低:TCP采用确认、重传等机制,传输效率相对较低,不适合传输实时性要求较高的数据。
  3. 数据量控制:TCP采用流量控制机制,可能会导致数据传输速度过慢,不适合传输大量数据时的性能要求。

UDP的优点:

  1. 传输效率高:UDP采用无连接、不可靠的传输方式,传输效率较高,适合传输实时性要求较高的数据。
  2. 简单快速:UDP没有连接建立和断开的过程,传输速度相对较快。
  3. 数据量控制:UDP没有流量控制机制,可以传输任意大小的数据。

UDP的缺点:

  1. 可靠性低:UDP没有确认、重传等机制,数据传输不可靠,数据包可能丢失或者乱序。
  2. 顺序性差:UDP传输的数据包可能会乱序,需要在应用层进行处理。
  3. 不适合传输大量数据:UDP传输的数据包大小有限制,不适合传输大量数据。
  4. 容易导致网络拥塞:UDP没有流量控制机制,容易导致网络拥塞,影响网络性能。

总之,TCP和UDP各有优缺点,在实际应用中需要根据具体的需求进行选择。如果需要传输大量的数据或保证数据的可靠传输,应该选择TCP;如果需要传输实时性要求较高的数据,或者需要提高传输效率,应该选择UDP。

1.2 TCP怎么保证可靠性?

  1. 序列号和确认号
    TCP使用序列号和确认号来保证数据的可靠传输。发送方给每个数据包分配一个唯一的序列号,接收方通过确认号告知发送方已经成功接收了数据包。当发送方收到接收方的确认信息后,就知道数据包已经成功传输。如果发送方没有收到确认信息,则会重新发送数据包,直到接收方成功接收为止。
  2. 数据包重传
    如果发送方没有收到确认信息,或者接收方发现数据包有丢失或损坏,TCP会自动重传数据包,以确保所有数据都被正确传输。在接收方发现数据包丢失或损坏后,会发送一个重复的确认信息告诉发送方需要重传数据包。发送方接收到重复的确认信息后,就知道需要重新发送数据包,以确保数据的可靠传输。
  3. 拥塞控制
    TCP使用拥塞控制机制来避免网络拥塞。当网络出现拥塞时,TCP会自动降低发送速率,以避免过多的数据包堵塞网络。TCP使用拥塞窗口(Congestion Window)来控制发送速率,当网络出现拥塞时,TCP会减小拥塞窗口的大小,以减缓发送速率。当网络恢复正常时,TCP会逐渐增大拥塞窗口的大小,以提高发送速率。
  4. 流量控制
    TCP使用流量控制机制来避免接收方被发送方的数据包淹没。接收方会发送窗口信息告诉发送方可以接收多少数据,发送方根据窗口信息控制发送速率。如果接收方的窗口大小为0,则发送方会停止发送数据,直到接收方的窗口大小变为非0为止。
  5. 超时重传
    TCP会对每个数据包设置一个超时时间,如果在超时时间内没有收到确认信息,则会重新发送数据包。当发送方发送数据包后,会启动一个超时计时器,在超时时间内如果没有收到确认信息,则会认为数据包丢失,需要重新发送。如果接收方收到了重复的数据包,则会忽略这些数据包,并发送一个重复的确认信息告诉发送方数据包已经正确接收。

1.3 TCP的建立连接和断开连接的过程

三次握手与四次挥手面试题
【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第1张图片

1.3.1 TCP建立连接

1.3.1.1 三次握手过程

参考链接:TCP的三次握手与四次挥手

最开始的时候客户端和服务器都是处于CLOSED状态。主动打开连接的为客户端,被动打开连接的是服务器。

  1. TCP服务器进程先创建传输控制块TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了LISTEN(监听)状态;
  2. TCP客户进程也是先创建传输控制块TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号seq=x ,此时,TCP客户端进程进入了SYN-SENT(同步已发送状态)状态。TCP规定,SYN报文段(SYN=1的报文段)不能携带数据,但需要消耗掉一个序号
  3. TCP服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该ACK=1,SYN=1,确认号是ack=x+1,同时也要为自己初始化一个序列号seq=y,此时,TCP服务器进程进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号
  4. TCP客户进程收到确认后,还要向服务器给出确认。确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时,TCP连接建立,客户端进入ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,但是如果不携带数据则不消耗序号
  5. 当服务器收到客户端的确认后也进入ESTABLISHED状态,此后双方就可以开始通信了。

【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第2张图片

1.3.1.2 为什么是三次握手?

主要从以下三个方面分析:

  1. 三次握手才可以阻止重复历史连接的初始化(主要原因);
  2. 三次握手才可以同步双方的初始序列号;
  3. 三次握手才可以避免资源浪费。

原因一:避免历史连接
TCP 使用三次握手建立连接的最主要原因就是防止「历史连接」初始化了连接。
如果是两次握手连接,就无法阻止历史连接。主要是因为在两次握手的情况下,服务端没有中间状态给客户端来阻止历史连接,导致服务端可能建立一个历史连接,造成资源浪费。
因此,要解决这种现象,最好就是在服务端发送数据前,也就是建立连接之前,要阻止掉历史连接,这样就不会造成资源浪费,而要实现这个功能,就需要三次握手。

原因二:同步双方初始序列号
TCP 协议的通信双方, 都必须维护一个「序列号」, 序列号是可靠传输的一个关键因素,它的作用:

  • 接收方可以去除重复的数据;
  • 接收方可以根据数据包的序列号按序接收;
  • 可以标识发送出去的数据包中, 哪些是已经被对方收到的(通过 ACK 报文中的序列号知道);

四次握手其实也能够可靠的同步双方的初始化序号,但由于第二步和第三步可以优化成一步,所以就成了「三次握手」。
而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。

原因三:避免资源浪费
如果只有「两次握手」,当客户端发生的 SYN 报文在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,由于没有第三次握手,服务端不清楚客户端是否收到了自己回复的 ACK 报文,所以服务端每收到一个 SYN 就只能先主动建立一个连接。
如果客户端发送的 SYN 报文在网络中阻塞了,重复发送多次 SYN 报文,那么服务端在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。

小结:
TCP 建立连接时,通过三次握手能防止历史连接的建立,能减少双方不必要的资源开销,能帮助双方同步初始化序列号。序列号能够保证数据包不重复、不丢弃和按序传输

不使用「两次握手」和「四次握手」的原因:

  • 「两次握手」:无法防止历史连接的建立,会造成双方资源的浪费,也无法可靠的同步双方序列号;
  • 「四次握手」:三次握手就已经理论上最少可靠连接建立,所以不需要使用更多的通信次数。

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

主要原因有两个方面:

  • 为了防止历史报文被下一个相同四元组的连接接收(主要方面)(并不是完全避免了,因为序列号会有回绕的问题,所以需要用时间戳的机制来判断历史报文);
  • 为了安全性,防止黑客伪造的相同序列号的 TCP 报文被对方接收;

1.3.1.4 初始序列号 ISN 是如何随机产生的?

起始 ISN 是基于时钟的,每 4 微秒 + 1,转一圈要 4.55 个小时。

RFC793 提到初始化序列号 ISN 随机生成算法:ISN = M + F(localhost, localport, remotehost, remoteport)。

  • M 是一个计时器,这个计时器每隔 4 微秒加 1。
  • F 是一个 Hash 算法,根据源 IP、目的 IP、源端口、目的端口生成一个随机数值。要保证 Hash 算法不能被外部轻易推算得出,用 MD5 算法是一个比较好的选择。

可以看到,随机数是会基于时钟计时器递增的,基本不可能会随机成一样的初始化序列号

1.3.1.5 什么是 SYN 攻击?如何避免 SYN 攻击?

假设攻击者短时间伪造不同 IP 地址的 SYN 报文,服务端每接收到一个 SYN 报文,就进入SYN_RCVD 状态,但服务端发送出去的 ACK + SYN 报文,无法得到未知 IP 主机的 ACK 应答,久而久之就会占满服务端的半连接队列,使得服务端不能为正常用户服务。
在 TCP 三次握手的时候,Linux 内核会维护两个队列,分别是:

  • 半连接队列,也称 SYN 队列;
  • 全连接队列,也称 accept 队列;
    【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第3张图片
    SYN 攻击方式最直接的表现就会把 TCP 半连接队列打满,这样当 TCP 半连接队列满了,后续再在收到 SYN 报文就会丢弃,导致客户端无法和服务端建立连接。

避免 SYN 攻击方式,可以有以下四种方法:

  • 调大 netdev_max_backlog;
    当网卡接收数据包的速度大于内核处理的速度时,会有一个队列保存这些数据包。控制该队列的最大值如下参数,默认值是 1000,我们要适当调大该参数的值,比如设置为 10000:
net.core.netdev_max_backlog = 10000
  • 增大 TCP 半连接队列;
    增大 TCP 半连接队列,要同时增大下面这三个参数:
    (1)增大 net.ipv4.tcp_max_syn_backlog
    (2)增大 listen() 函数中的 backlog
    (3)增大 net.core.somaxconn
  • 开启 tcp_syncookies;
    开启 syncookies 功能就可以在不使用 SYN 半连接队列的情况下成功建立连接,相当于绕过了 SYN 半连接来建立连接。
  • 减少 SYN+ACK 重传次数

1.3.2 TCP断开连接

1.3.2.1 四次挥手过程

  1. 客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。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连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
  6. 服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
    这里一点需要注意是:主动关闭连接的,才有 TIME_WAIT 状态
    【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第4张图片

1.3.2.2 为什么挥手需要四次?

  • 关闭连接时,客户端向服务端发送 FIN 时,仅仅表示客户端不再发送数据了但是还能接收数据。
  • 服务端收到客户端的 FIN 报文时,先回一个 ACK 应答报文,而服务端可能还有数据需要处理和发送,等服务端不再发送数据时,才发送 FIN 报文给客户端来表示同意现在关闭连接。
    从上面过程可知,服务端通常需要等待完成数据的发送和处理,所以服务端的 ACK 和 FIN 一般都会分开发送,因此是需要四次挥手。

1.3.2.3 为什么 TIME_WAIT 等待的时间是 2MSL?

MSL (Maximum Segment Lifetime) 报文最大生存时间,它是任何报文在网络上存在的最长时间,超过这个时间报文将被丢弃。因为 TCP 报文基于是 IP 协议的,而 IP 头中有一个 TTL 字段,是 IP 数据报可以经过的最大路由数,每经过一个处理他的路由器此值就减 1,当此值为 0 则数据报将被丢弃,同时发送 ICMP 报文通知源主机。
MSL 与 TTL 的区别: MSL 的单位是时间,而 TTL 是经过路由跳数。所以 MSL 应该要大于等于 TTL 消耗为 0 的时间,以确保报文已被自然消亡。
TTL 的值一般是 64,Linux 将 MSL 设置为 30 秒,意味着 Linux 认为数据报文经过 64 个路由器的时间不会超过 30 秒,如果超过了,就认为报文已经消失在网络中了。

TIME_WAIT 等待 2 倍的 MSL,比较合理的解释是: 网络中可能存在来自发送方的数据包,当这些发送方的数据包被接收方处理后又会向对方发送响应,所以一来一回需要等待 2 倍的时间

1.3.2.4 为什么需要 TIME_WAIT 状态?

主动发起关闭连接的一方,才会有 TIME-WAIT 状态。需要 TIME-WAIT 状态,主要是两个原因:

  • 防止历史连接中的数据,被后面相同四元组的连接错误的接收;
  • 保证「被动关闭连接」的一方,能被正确的关闭;

1.3.2.5 TIME_WAIT 过多有什么危害?

过多的 TIME-WAIT 状态主要的危害有两种:

  • 第一是占用系统资源,比如文件描述符、内存资源、CPU 资源、线程资源等;
  • 第二是占用端口资源,端口资源也是有限的,一般可以开启的端口为 32768~61000,也可以通过 net.ipv4.ip_local_port_range参数指定范围。

1.3 ISO/OSI模型、TCP/IP协议和模型

【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第5张图片

1.3.1 OSI七层网络和TCPIP网络模型区别

OSI七层网络模型和TCP/IP网络模型都是网络通信方面的标准模型,但它们之间存在一些区别:

  1. 层数不同:OSI七层网络模型由下至上分别为物理层、数据链路层、网络层、传输层、会话层、表示层和应用层,共七层。而TCP/IP网络模型由下至上分别为物理层、数据链路层、网络层、传输层和应用层,共五层。

  2. 名称不同:OSI七层网络模型中的每一层都有独立的名称和功能,而TCP/IP网络模型中的每一层通常只有一个名称,有时也称为协议族。

  3. 组成不同:OSI七层网络模型是一个理论模型,没有具体的协议实现,而TCP/IP网络模型是一个实际使用的模型,具有大量的协议实现,如TCP、IP、UDP等。

  4. 技术发展不同:OSI七层网络模型是由国际标准化组织(ISO)在20世纪80年代开发的,而TCP/IP网络模型是在20世纪70年代由美国国防部开发的。

  5. 通信方式不同:OSI七层网络模型中的每一层都是独立的,通信方式是通过每一层之间的接口进行数据传输;而TCP/IP网络模型中的每一层不完全独立,通信方式是通过封装和解封装数据包来实现数据传输。

二、HTTP

2.1 HTTP概念

HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件,图片文件,查询结果等)。
HTTP是一个属于应用层的面向对象的协议,由于其简捷、快速的方式,适用于分布式超媒体信息系统。
它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展。目前在WWW中使用的是HTTP/1.0的第六版,HTTP/1.1的规范化工作正在进行之中,而且HTTP-NG(Next Generation of HTTP)的建议已经提出。
HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。

HTTP 是一个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」。

2.2 GET 与 POST

2.2.1 GET 和 POST 有什么区别?

根据 RFC 规范,GET 的语义是从服务器获取指定的资源,这个资源可以是静态的文本、页面、图片视频等。GET 请求的参数位置一般是写在 URL 中,URL 规定只能支持 ASCII,所以 GET 请求的参数只允许 ASCII 字符 ,而且浏览器会对 URL 的长度有限制(HTTP协议本身对 URL长度并没有做任何规定)。
根据 RFC 规范,POST 的语义是根据请求负荷(报文body)对指定的资源做出处理,具体的处理方式视资源类型而不同。POST 请求携带数据的位置一般是写在报文 body 中,body 中的数据可以是任意格式的数据,只要客户端与服务端协商好即可,而且浏览器不会对 body 大小做限制。

2.2.2 GET 和 POST 方法都是安全和幂等的吗?

安全和幂等的概念:

  • 在 HTTP 协议里,所谓的「安全」是指请求方法不会「破坏」服务器上的资源。
  • 所谓的「幂等」,意思是多次执行相同的操作,结果都是「相同」的。

如果从 RFC 规范定义的语义来看:

  • GET 方法就是安全且幂等的,因为它是「只读」操作,无论操作多少次,服务器上的数据都是安全的,且每次的结果都是相同的。所以,可以对 GET 请求的数据做缓存,这个缓存可以做到浏览器本身上(彻底避免浏览器发请求),也可以做到代理上(如nginx),而且在浏览器中 GET 请求可以保存为书签。
  • POST 因为是「新增或提交数据」的操作,会修改服务器上的资源,所以是不安全的,且多次提交数据就会创建多个资源,所以不是幂等的。所以,浏览器一般不会缓存 POST 请求,也不能把 POST 请求保存为书签。

但是实际过程中,开发者不一定会按照 RFC 规范定义的语义来实现 GET 和 POST 方法。比如:

  • 可以用 GET 方法实现新增或删除数据的请求,这样实现的 GET 方法自然就不是安全和幂等。
  • 可以用 POST 方法实现查询数据的请求,这样实现的 POST 方法自然就是安全和幂等。

2.3 HTTP 缓存技术

2.3.1 HTTP 缓存有哪些实现方式?

对于一些具有重复性的 HTTP 请求,比如每次请求得到的数据都一样的,我们可以把这对「请求-响应」的数据都缓存在本地,那么下次就直接读取本地的数据,不必在通过网络获取服务器的响应了,这样的话 HTTP/1.1 的性能肯定肉眼可见的提升。

所以,避免发送 HTTP 请求的方法就是通过缓存技术,HTTP 设计者早在之前就考虑到了这点,因此 HTTP 协议的头部有不少是针对缓存的字段。

HTTP 缓存有两种实现方式,分别是强制缓存和协商缓存

2.3.2 什么是强制缓存?

强缓存指的是只要浏览器判断缓存没有过期,则直接使用浏览器的本地缓存,决定是否使用缓存的主动性在于浏览器这边。
如下图中,返回的是 200 状态码,但在 size 项中标识的是 from disk cache,就是使用了强制缓存。
【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第6张图片
强缓存是利用下面这两个 HTTP 响应头部(Response Header)字段实现的,它们都用来表示资源在客户端缓存的有效期:

  • Cache-Control, 是一个相对时间;
  • Expires,是一个绝对时间;

如果 HTTP 响应头部同时有 Cache-Control 和 Expires 字段的话,Cache-Control 的优先级高于 Expires 。

Cache-control 选项更多一些,设置更加精细,所以建议使用 Cache-Control 来实现强缓存。具体的实现流程如下:

  • 当浏览器第一次请求访问服务器资源时,服务器会在返回这个资源的同时,在 Response 头部加上 Cache-Control,Cache-Control 中设置了过期时间大小;
  • 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间大小,来计算出该资源是否过期,如果没有,则使用该缓存,否则重新请求服务器;
  • 服务器再次收到请求后,会再次更新 Response 头部的 Cache-Control。

2.3.3 什么是协商缓存?

协商缓存可以基于两种头部来实现。

第一种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现,这两个字段的意思是:

  • 响应头部中的 Last-Modified:标示这个响应资源的最后修改时间;
  • 请求头部中的 If-Modified-Since:当资源过期了,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 Last-Modified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比(Last-Modified),如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无新修改,响应 HTTP 304 走缓存。

第二种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段,这两个字段的意思是:

  • 响应头部中 Etag:唯一标识响应资源;
  • 请求头部中的 If-None-Match:当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头 If-None-Match 值设置为 Etag 的值。服务器收到请求后进行比对,如果资源没有变化返回 304,如果资源变化了返回 200。

2.4 HTTP 特性(HTTP/1.1 )

2.4.1 HTTP/1.1 的优点有哪些?

HTTP 最突出的优点是「简单、灵活和易于扩展、应用广泛和跨平台」。

  1. 简单
    HTTP 基本的报文格式就是 header + body,头部信息也是 key-value 简单文本的形式,易于理解,降低了学习和使用的门槛。

  2. 灵活和易于扩展
    HTTP 协议里的各类请求方法、URI/URL、状态码、头字段等每个组成要求都没有被固定死,都允许开发人员自定义和扩充。
    同时 HTTP 由于是工作在应用层( OSI 第七层),则它下层可以随意变化,比如:
    HTTPS 就是在 HTTP 与 TCP 层之间增加了 SSL/TLS 安全传输层;
    HTTP/1.1 和 HTTP/2.0 传输协议使用的是 TCP 协议,而到了 HTTP/3.0 传输协议改用了 UDP 协议。

  3. 应用广泛和跨平台
    互联网发展至今,HTTP 的应用范围非常的广泛,从台式机的浏览器到手机上的各种 APP,从看新闻、刷贴吧到购物、理财、吃鸡,HTTP 的应用遍地开花,同时天然具有跨平台的优越性。

2.4.2 HTTP/1.1 的缺点有哪些?

HTTP 协议里有优缺点一体的双刃剑,分别是「无状态、明文传输」,同时还有一大缺点「不安全」。

  1. 无状态双刃剑
    无状态的好处,因为服务器不会去记忆 HTTP 的状态,所以不需要额外的资源来记录状态信息,这能减轻服务器的负担,能够把更多的 CPU 和内存用来对外提供服务。
    无状态的坏处,既然服务器没有记忆能力,它在完成有关联性的操作时会非常麻烦。
    对于无状态的问题,解法方案有很多种,其中比较简单的方式用 Cookie 技术。
    Cookie 通过在请求和响应报文中写入 Cookie 信息来控制客户端的状态。

  2. 明文传输双刃剑
    明文意味着在传输过程中的信息,是可方便阅读的,比如 Wireshark 抓包都可以直接肉眼查看,为我们调试工作带了极大的便利。
    但是这正是这样,HTTP 的所有信息都暴露在了光天化日下,相当于信息裸奔。在传输的漫长的过程中,信息的内容都毫无隐私可言,很容易就能被窃取,如果里面有你的账号密码信息,那你号没了。

  3. 不安全
    HTTP 比较严重的缺点就是不安全:

  • 通信使用明文(不加密),内容可能会被窃听。比如,账号信息容易泄漏,那你号没了。
  • 不验证通信方的身份,因此有可能遭遇伪装。比如,访问假的淘宝、拼多多,那你钱没了。
  • 无法证明报文的完整性,所以有可能已遭篡改。比如,网页上植入垃圾广告,视觉污染,眼没了。
    HTTP 的安全问题,可以用 HTTPS 的方式解决,也就是通过引入 SSL/TLS 层,使得在安全上达到了极致。

2.4.3 HTTP/1.1 的性能如何?

  1. 长连接

早期 HTTP/1.0 性能上的一个很大的问题,那就是每发起一个请求,都要新建一次 TCP 连接(三次握手),而且是串行请求,做了无谓的 TCP 连接建立和断开,增加了通信开销。
为了解决上述 TCP 连接问题,HTTP/1.1 提出了长连接的通信方式,也叫持久连接。这种方式的好处在于减少了 TCP 连接的重复建立和断开所造成的额外开销,减轻了服务器端的负载。
持久连接的特点是,只要任意一端没有明确提出断开连接,则保持 TCP 连接状态。

  1. 管道网络传输

HTTP/1.1 采用了长连接的方式,这使得管道(pipeline)网络传输成为了可能。
即可在同一个 TCP 连接里面,客户端可以发起多个请求,只要第一个请求发出去了,不必等其回来,就可以发第二个请求出去,可以减少整体的响应时间。
举例来说,客户端需要请求两个资源。以前的做法是,在同一个 TCP 连接里面,先发送 A 请求,然后等待服务器做出回应,收到后再发出 B 请求。那么,管道机制则是允许浏览器同时发出 A 请求和 B 请求,

但是服务器必须按照接收请求的顺序发送对这些管道化请求的响应。
如果服务端在处理 A 请求时耗时比较长,那么后续的请求的处理都会被阻塞住,这称为「队头堵塞」。
所以,HTTP/1.1 管道解决了请求的队头阻塞,但是没有解决响应的队头阻塞。

注意:
实际上 HTTP/1.1 管道化技术不是默认开启,而且浏览器基本都没有支持,有这个功能,但是没有被使用.

  1. 队头阻塞
    「请求 - 应答」的模式会造成 HTTP 的性能问题。为什么呢?
    因为当顺序发送的请求序列中的一个请求因为某种原因被阻塞时,在后面排队的所有请求也一同被阻塞了,会招致客户端一直请求不到数据,这也就是「队头阻塞」。

2.5 HTTP 与 HTTPS

2.5.1 HTTP 与 HTTPS 有哪些区别?

  • HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 则解决 HTTP 不安全的缺陷,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
  • HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
  • 两者的默认端口不一样,HTTP 默认端口号是 80,HTTPS 默认端口号是 443。
  • HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。

2.5.2 HTTPS 解决了 HTTP 的哪些问题?

HTTP 由于是明文传输,所以安全上存在以下三个风险:

  • 窃听风险,比如通信链路上可以获取通信内容,用户号容易没。
  • 篡改风险,比如强制植入垃圾广告,视觉污染,用户眼容易瞎。
  • 冒充风险,比如冒充淘宝网站,用户钱容易没。

HTTPS 在 HTTP 与 TCP 层之间加入了 SSL/TLS 协议,可以很好的解决了上述的风险:

  • 信息加密:交互信息无法被窃取,但你的号会因为「自身忘记」账号而没。
  • 校验机制:无法篡改通信内容,篡改了就不能正常显示,但百度「竞价排名」依然可以搜索垃圾广告。
  • 身份证书:证明淘宝是真的淘宝网,但你的钱还是会因为「剁手」而没。
  1. 混合加密
    通过混合加密的方式可以保证信息的机密性,解决了窃听的风险。

HTTPS 采用的是对称加密和非对称加密结合的「混合加密」方式:

  • 在通信建立前采用非对称加密的方式交换「会话秘钥」,后续就不再使用非对称加密。
  • 在通信过程中全部使用对称加密的「会话秘钥」的方式加密明文数据。

采用「混合加密」的方式的原因:

  • 对称加密只使用一个密钥,运算速度快,密钥必须保密,无法做到安全的密钥交换。
  • 非对称加密使用两个密钥:公钥和私钥,公钥可以任意分发而私钥保密,解决了密钥交换问题但速度慢。
  1. 摘要算法 + 数字签名

为了保证传输的内容不被篡改,我们需要对内容计算出一个「指纹」,然后同内容一起传输给对方。

对方收到后,先是对内容也计算出一个「指纹」,然后跟发送方发送的「指纹」做一个比较,如果「指纹」相同,说明内容没有被篡改,否则就可以判断出内容被篡改了。

那么,在计算机里会用摘要算法(哈希函数)来计算出内容的哈希值,也就是内容的「指纹」,这个哈希值是唯一的,且无法通过哈希值推导出内容。

通过哈希算法可以确保内容不会被篡改,但是并不能保证「内容 + 哈希值」不会被中间人替换,因为这里缺少对客户端收到的消息是否来源于服务端的证明。

那为了避免这种情况,计算机里会用非对称加密算法来解决,共有两个密钥:

  • 一个是公钥,这个是可以公开给所有人的;
  • 一个是私钥,这个必须由本人管理,不可泄露。

这两个密钥可以双向加解密的,比如可以用公钥加密内容,然后用私钥解密,也可以用私钥加密内容,公钥解密内容。

流程的不同,意味着目的也不相同:

公钥加密,私钥解密。这个目的是为了保证内容传输的安全,因为被公钥加密的内容,其他人是无法解密的,只有持有私钥的人,才能解密出实际的内容;
私钥加密,公钥解密。这个目的是为了保证消息不会被冒充,因为私钥是不可泄露的,如果公钥能正常解密出私钥加密的内容,就能证明这个消息是来源于持有私钥身份的人发送的。
一般我们不会用非对称加密来加密实际的传输内容,因为非对称加密的计算比较耗费性能的。

所以非对称加密的用途主要在于通过「私钥加密,公钥解密」的方式,来确认消息的身份,我们常说的数字签名算法,就是用的是这种方式,不过私钥加密内容不是内容本身,而是对内容的哈希值加密。

  1. 数字证书

【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第7张图片

2.5.3 HTTPS 是如何建立连接的?其间交互了什么?

SSL/TLS 协议基本流程:

  • 客户端向服务器索要并验证服务器的公钥。
  • 双方协商生产「会话秘钥」。
  • 双方采用「会话秘钥」进行加密通信。
    前两步也就是 SSL/TLS 的建立过程,也就是 TLS 握手阶段。TLS 的「握手阶段」涉及四次通信,使用不同的密钥交换算法,TLS 握手流程也会不一样的,现在常用的密钥交换算法有两种:RSA 算法和 ECDHE 算法。

HTTPS建立连接的过程如下:

  1. 客户端向服务器发送一个HTTPS请求。
  2. 服务器将其公钥和数字证书发送给客户端。数字证书通常是由可信任的证书颁发机构(CA)签发的,用于证明服务器的身份。
  3. 客户端验证证书的有效性,如果证书有效且可信,则生成随机的对称加密密钥,并使用服务器公钥进行加密,发送给服务器。
  4. 服务器使用私钥解密客户端发送的数据,获取对称加密密钥,并将其用于后续通信的加密和解密。
  5. 双方使用对称加密密钥进行加密和解密数据的通信,保证通信过程的安全性和保密性。

在HTTPS建立连接的过程中,客户端和服务器之间进行了以下交互:

  1. 客户端向服务器发送请求,请求建立HTTPS连接。
  2. 服务器发送数字证书和公钥给客户端。
  3. 客户端验证证书的有效性,并使用服务器公钥加密生成的对称加密密钥,发送给服务器。
  4. 服务器使用私钥解密客户端发送的数据,获取对称加密密钥。
  5. 双方使用对称加密密钥进行加密和解密数据的通信。

2.5.4 HTTPS 的应用数据是如何保证完整性的?

具体过程如下:

  • 首先,消息被分割成多个较短的片段,然后分别对每个片段进行压缩。
  • 接下来,经过压缩的片段会被加上消息认证码(MAC 值,这个是通过哈希算法生成的),这是为了保证完整性,并进行数据的认证。通过附加消息认证码的 MAC 值,可以识别出篡改。与此同时,为了防止重放攻击,在计算消息认证码时,还加上了片段的编码。
  • 再接下来,经过压缩的片段再加上消息认证码会一起通过对称密码进行加密。
  • 最后,上述经过加密的数据再加上由数据类型、版本号、压缩后的长度组成的报头就是最终的报文数据。

记录协议完成后,最终的报文数据将传递到传输控制协议 (TCP) 层进行传输。

2.5.5 HTTPS 一定安全可靠吗?

HTTPS 协议本身到目前为止还是没有任何漏洞的,即使你成功进行中间人攻击,本质上是利用了客户端的漏洞(用户点击继续访问或者被恶意导入伪造的根证书),并不是 HTTPS 不够安全。

为什么抓包工具能截取 HTTPS 数据?

很多抓包工具 之所以可以明文看到 HTTPS 数据,工作原理与中间人一致的。对于 HTTPS 连接来说,中间人要满足以下两点,才能实现真正的明文代理:

  • 中间人,作为客户端与真实服务端建立连接这一步不会有问题,因为服务端不会校验客户端的身份;
  • 中间人,作为服务端与真实客户端建立连接,这里会有客户端信任服务端的问题,也就是服务端必须有对应域名的私钥;

中间人要拿到私钥只能通过如下方式:

  1. 去网站服务端拿到私钥;
  2. 去CA处拿域名签发私钥;
  3. 自己签发证书,切要被浏览器信任.

抓包工具只能使用第三种方式取得中间人的身份。使用抓包工具进行 HTTPS 抓包的时候,需要在客户端安装 Fiddler 的根证书,这里实际上起认证中心(CA)的作用。

抓包工具能够抓包的关键是客户端会往系统受信任的根证书列表中导入抓包工具生成的证书,而这个证书会被浏览器信任,也就是抓包工具给自己创建了一个认证中心 CA,客户端拿着中间人签发的证书去中间人自己的 CA 去认证,当然认为这个证书是有效的。

如何避免被中间人抓取数据?

我们要保证自己电脑的安全,不要被病毒乘虚而入,而且也不要点击任何证书非法的网站,这样 HTTPS 数据就不会被中间人截取到了。
当然,我们还可以通过 HTTPS 双向认证来避免这种问题。
一般我们的 HTTPS 是单向认证,客户端只会验证了服务端的身份,但是服务端并不会验证客户端的身份。

三、网络编程

3.1 客户端和服务器端相关函数

3.1.1 基于TCP

【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第8张图片

TCP协议的服务器端常用的Socket函数:

  1. socket():创建套接字
  2. bind():将套接字与IP地址和端口号绑定
  3. listen():开始监听客户端连接请求
  4. accept():接受客户端连接请求
  5. recv():接收客户端发来的数据
  6. send():向客户端发送数据
  7. getsockopt():获取Socket选项
  8. setsockopt():设置Socket选项
  9. close():关闭套接字

TCP协议的客户端常用的Socket函数:

  1. socket():创建套接字
  2. connect():向服务器端发起连接请求
  3. send():向服务器端发送数据
  4. recv():接收服务器端返回的数据
  5. getsockopt():获取Socket选项
  6. setsockopt():设置Socket选项
  7. close():关闭套接字

3.1.2 基于UDP

【嵌入式笔/面试】嵌入式软件基础题和真题总结——网络相关_第9张图片

UDP协议的服务器端常用的Socket函数:

  1. socket():创建套接字
  2. bind():将套接字与IP地址和端口号绑定
  3. recvfrom():接收客户端发来的数据
  4. sendto():向客户端发送数据
  5. getsockopt():获取Socket选项
  6. setsockopt():设置Socket选项
  7. close():关闭套接字

UDP协议的客户端常用的Socket函数:

  1. socket():创建套接字
  2. sendto():向服务器端发送数据
  3. recvfrom():接收服务器端返回的数据
  4. getsockopt():获取Socket选项
  5. setsockopt():设置Socket选项
  6. close():关闭套接字

3.1.3 TCP和UDP中客户端和服务器端使用的函数差异

TCP协议的客户端和服务器端常用的Socket函数:

  1. 客户端需要使用connect()函数向服务器端发起连接请求,而服务器端需要使用accept()函数接受客户端的连接请求。
  2. 数据传输是面向连接的,因此在进行数据传输之前需要先建立连接,客户端和服务器端都需要使用send()函数和recv()函数进行数据的发送和接收。
  3. 服务器端需要使用listen()函数开始监听客户端连接请求,并使用bind()函数将套接字与特定的IP地址和端口号绑定。

UDP协议的客户端和服务器端常用的Socket函数:

  1. 客户端和服务器端都不需要建立连接,客户端可以直接使用sendto()函数向服务器端发送数据,服务器端也可以直接使用recvfrom()函数接收客户端发送的数据。
  2. 数据传输是无连接的,因此客户端和服务器端都可以使用sendto()函数和recvfrom()函数进行数据的发送和接收。
  3. 服务器端需要使用bind()函数将套接字与特定的IP地址和端口号绑定,并使用recvfrom()函数接收客户端发送的数据。

3.2 Socket编程的send() recv() accept() socket()函数

  1. socket()函数:
    socket()函数用于创建一个新的套接字(socket),并指定套接字的类型和协议。该函数返回一个整数值用于标识新创建的套接字。在使用socket()函数时,需要指定套接字的类型(如SOCK_STREAM表示TCP协议,SOCK_DGRAM表示UDP协议),以及套接字所使用的协议(如IPPROTO_TCP表示使用TCP协议)。

  2. send()函数:
    send()函数用于向已连接的套接字发送数据。该函数需要指定发送数据的套接字描述符、要发送的数据指针和数据长度等参数。send()函数返回实际发送的数据长度,如果发送失败则返回-1。

  3. recv()函数:
    recv()函数用于从已连接的套接字接收数据。该函数需要指定接收数据的套接字描述符、接收数据的缓冲区指针和缓冲区长度等参数。recv()函数返回实际接收到的数据长度,如果接收失败则返回-1。

  4. accept()函数:
    accept()函数用于接受客户端的连接请求,并创建一个新的套接字用于与客户端通信。该函数需要指定服务器端的套接字描述符和一个用于存放客户端地址信息的结构体指针等参数。accept()函数返回一个新的套接字描述符,用于与客户端进行通信。

3.3 网络编程中长链接和短链接

在网络编程中,长链接和短链接是两种不同的连接方式,它们的区别主要在于连接的建立和维护方式

  1. 长链接
    长链接是指客户端和服务器端建立的连接可以在一段时间内一直保持打开状态,以便于多次发送和接收数据。在长链接中,连接的建立和维护需要一定的资源和时间成本,但可以避免频繁地建立和关闭连接,从而提高通信效率。长链接通常用于需要频繁通信的场景,如在线游戏、即时通讯等。

  2. 短链接
    短链接是指客户端和服务器端每次发送和接收数据都需要建立一个新的连接,完成数据传输后立即关闭连接。在短链接中,连接的建立和维护成本较低,但频繁地建立和关闭连接也会影响通信效率。短链接通常用于数据传输量较小、通信频率较低的场景,如HTTP请求等。

你可能感兴趣的:(嵌入式开发面试笔试总结笔记,面试,网络,tcp/ip)