计算机网络面试知识点总结
目录
- 1. 计算机网络的基本知识点
- 2. OSI 七层模型
- 3. TCP/IP 四层模型
- 4. TCP 和 UDP
- 4.1 TCP 协议
- 4.2 TCP 流量控制
- 4.3 TCP 拥塞控制
- 4.4 TCP 三次握手
- 4.5 TCP 四次挥手
- 4.6 TCP 粘包问题
- 4.7 TCP Socket交互流程
- 4.8 UDP 协议以及和 TCP 协议的不同
- 5. HTTP协议
- 5.1 HTTP 请求方法以及过程和原理
- 5.2 HTTP 状态码
- 5.3 HTTP 缓存
- 5.4 HTTP 报文格式
- 5.5 Cookie 和 Session 区别
- 5.6 Session 的实现原理
- 5.7 HTTP/1.1
- 5.8 HTTP/2.0
- 5.9 HTTP/1.0,1.1,2.0 的区别?
- 5.10 HTTP/3 / QUIC
- 6. HTTPS
- 6.1 SSL/TLS
- 6.2 RSA 密钥交换算法
- 7. DNS
- 8. IP协议
- 9. WebSocket
- 10. DHCP
- 11. NET
- 12. IGMP
1. 计算机网络的基本知识点
(1)计算机网络的一些名词介绍:
- MSL(Maximum segment lifetime):TCP 报文最大生存时间。它是任何 TCP 报文在网络上存在的最长时间,超过这个时间报文将被丢弃。实际应用中常用的设置是 30 秒,1 分钟和 2 分钟。
- TTL(Time to live):IP 数据报在网络中可以存活的总跳数,称为“生存时间”,但并不是⼀个真正的时间。该域由源主机设置初始值,每经过⼀个路由器,跳数减 1,如果减至 0,则丢弃该数据包,同时发送 ICMP 报文通知源主机。取值范围 1-255。
- RTT(Round trip time):客户端到服务端往返所花时间。RTT 受网络传输拥塞的变化而变化,由TCP 动态地估算。
- 字节序:现代CPU的累加器⼀次都能装载(至少)8字节(64位机器),那么这8字节在内存中排序的顺序将影响它被累加器装载成的整数的值,这就是字节序问题。字节序分为大端字节序和小端字节序。
- 大端字节序是指⼀个整数的高位字节存储在内存的低地址处,低位字节存储在内存的高地址处。
- 小端字节序反之。现代PC大多采用小端字节序,因此 小端字节序 有被称为 主机字节序。需要指出的是,即使是同⼀台机器上的两个进程通信,也要考虑字节序的问题(JAVA虚拟机采用大端字节序)。网际协议使用大端字节序来传送数据。
void show_bytes(char* start, size_t len)
{for (size_t i = 0; i < len; i++) {printf("%.2x ", start[i]);}
}void show_int(int x)
{show_bytes((char*)&x, sizeof(int));
}int main()
{show_int(12345);return 0;
}
- 12345 的十六进制表示为 0x00003039,在不同机器上的输出值如下:【高地址—>低地址】
Linux 上先输出最低有效字节,说明它是小端机器。
- 正向代理:要求客户端自己设置代理服务器的地址。客户的每次请求都将直接发送到该代理服务器,并由代理服务器请求目标资源。比如处于防火墙内的局域网机器要访问互联网,或者要访问⼀些被屏蔽掉的国外网站,就需要使用正向代理服务器。
- 反向代理:被设置在服务端,因而客户端无须进行任何设置。反向代理是指用代理服务器来接受互联网上的连接请求,然后将请求转发给内部网络上的服务器,并将从内部服务器上得到的结果返回给客户端。这种情况下,代理服务器对外就表现为⼀个真实的服务器。各大网站通常分区域设置了多个代理服务器,所以在不同地方ping同⼀个域名可能得到不同的 IP 地址,因为这些 IP 地址实际上是代理服务器的 IP 地址。
(2)从输入一个 URL 到页面加载完成的过程(详细的URL介绍见博客《HTTP协议》):
- DNS 解析:将域名解析成对应的 IP 地址。
- TCP连接:与服务器通过三次握手,建立 TCP 连接
- 向服务器发送 HTTP 请求
- 服务器处理请求,返回HTTp响应
- 浏览器解析并渲染页面
- 断开连接:TCP 四次挥手,连接结束
- 也可以阅读这篇文章:键入网址到网页显示,期间发生了什么?
(3)浏览器:
- 浏览器是多进程的。浏览器只有⼀个主进程,负责创建/管理其他进程、显示浏览器主窗口、下载网络资源等。
- 每打开⼀个标签页,就创建了⼀个独立的浏览器渲染进程。浏览器渲染进程又称为浏览器内核,其内部是多线程的,负责页面渲染、脚本执行等。
- 浏览器的每⼀个网络请求,都需要主进程开辟⼀个单独的网络线程去处理。输入 URL 相当于⼀个网络请求,解析 HTML 时遇到 JS/CSS/图片等静态资源的引用链接,也需要分别请求。
(4)服务器需要负载均衡:大型的项目,往往是由多台服务器组成⼀个集群,以此应对庞大的并发访问量。这种情况下,用户的请求都会指向调度服务器,由调度服务器将请求分发给集群中的某台服务器 A,然后调度服务器会将 A 服务器的 HTTP 响应发送给用户。负载均衡算法有:
- 轮询(Round Robin):把每个请求轮流发送到每个服务器上。
- 加权轮询(Weighted Round Robbin):根据服务器性能对其加入权重。
- 最少连接(Least Connections)。
- 加权最少连接(Weighted Least Connection)。
- 随机算法(Random)。
- 源地址哈希法(IP Hash):对客户端IP计算哈希值之后,再对服务器数量取模得到目标服务器的序号。可以保证同-IP的客户端的请求会转发到同⼀台服务器上,用来实现会话粘滞(Sticky Session)。
(5)说下计算机网络体系结构有哪些??
- 计算机网络体系结构,一般有三种:OSI 七层模型、TCP/IP 四层模型、五层结构。后面会逐个介绍。
(6)那么数据在各层之间是怎么传输的呢?(详细介绍见博客《网络基础入门》的第4小节)
- 对于发送方而言,从上层到下层层层包装,对于接收方而言,从下层到上层,层层解开包装。
- 发送方的应用进程向接收方的应用进程传送数据。
- AP先将数据交给本主机的应用层,应用层加上本层的控制信息H5就变成了下一层的数据单元。
- 传输层收到这个数据单元后,加上本层的控制信息H4,再交给网络层,成为网络层的数据单元。
- 到了数据链路层,控制信息被分成两部分,分别加到本层数据单元的首部(H2)和尾部(T2)。
- 最后的物理层,进行比特流的传输。
2. OSI 七层模型
(1)七层模型的介绍如下(详细的介绍见博客《网络基础入门》):
- 物理层:确保原始的数据可以在各种物理媒介上传输。这⼀层是 bit 流。传输协议有 IEEE 802.1A等
- 数据链路层:在不可靠的物理介质上提供可靠的传输。包括物理地址寻址、流量控制、数据的检错和重发等。这⼀层将 bit 流封装成 frame 帧。传输协议有 MAC 等
- 网络层:负责对子网间的数据包进行路由选择,目的是实现两个端系统之间的数据透明传送。这⼀层数据的单位为数据包。协议有 IP、ICMP、ARP、RARP 等
- 传输层:负责将上层数据分段并提供端到端的传输。这⼀层数据的单位称为数据段(segment)。传输协议有 TCP、UDP 等
- 会话层:管理主机之间的会话进程,如建立会话、session认证、断点续传等。传输协议有 SMTP等
- 表示层:主要解决用户信息的语法表示问题。数据的压缩和解压缩、加密和解密等工作由该层负责。
- 应用层:为操作系统或网络应用程序提供访问网络服务的接口。传输协议有 FTP、HTTP、Telnet、DNS等
3. TCP/IP 四层模型
(1)TCP/IP 协议族是四层协议系统,自底向上分别是 数据链路层(物理层+数据链路层)、网络层、传输层 和 应用层。详细的介绍见博客《网络基础入门》的3.3小节
4. TCP 和 UDP
(1)唯一确定TCP:协议类型、源ip地址、目标ip地址、源端口、目标端口。更加详细的介绍见博客《TCP协议》和《UDP协议》。
4.1 TCP 协议
(1)TCP 为什么是面向连接的?
- 发送之前需要先建立连接(三次握手)。
- 使用排序和确认机制(分组之间并不是独立的;记录了分组之间的状态信息)。
- 具有流量控制与拥塞控制。
- 发送完毕后要释放连接(四次挥手)。
(2)TCP 如何保证传输的可靠性?各个模块的介绍见博客《TCP协议》
- 三次握手:确认通信实体存在。
- 序列号 / 确认应答:解决乱序问题。
- 确认号 / 超时重传机制:解决丢包问题。
- 数据校验(校验和):保证传输数据的正确。
(3)有⼀个 IP 的服务器监听了一个端口,它的 TCP 的最大连接数是多少??
- 服务器通常固定在某个本地端口上监听,等待客户端的连接请求。因此,客户端 IP 和 端口是可变的,其理论值计算公式如下:
- 对 IPv4,客户端的 IP 数最多为 2^32,客户端的端口数最多为 2^16,也就是服务端单机最大 TCP 连接数,约为 2^48。
(4)当然,服务端最大并发 TCP 连接数远不能达到理论上限,会受以下因素影响:
-
文件描述符限制,每个 TCP 连接都是⼀个文件,如果文件描述符被占满了,会发生 too manyopen files。Linux 对可打开的文件描述符的数量分别作了三个方面的限制:
- 系统级:当前系统可打开的最大数量,通过 cat /proc/sys/fs/file-max 查看;
- 用户级:指定用户可打开的最大数量,通过 cat /etc/security/limits.conf 查看;
- 进程级:单个进程可打开的最大数量,通过 cat /proc/sys/fs/nr_open 查看;
-
内存限制,每个 TCP 连接都要占用⼀定内存,操作系统的内存是有限的,如果内存资源被占满后,会发生 OOM。
(5)TCP 首部格式。有 20 字节固定首部:
- 序列号(32bit):在建立连接时由计算机生成的随机数作为其初始值,通过 SYN 包传给接收端主机,每发送⼀次数据,就「累加」一次该「数据字节数」的大小,用于解决乱序问题。例如序号为301,表示第一个字节的编号是301,如果携带的数据长度为100字节,那么下一个报文段的序号应为401
- 确认号(32bit):接收方对发送方TCP报文段的响应,值为序号值加一。
- 首部长(4bit):标识首部有多大,最大为15,即60字节。
- 标志位 URG(6bit):紧急标志,用于保证 TCP 连接不被中断,并且督促中间层设备尽快处理。
- 标志位 ACK(6bit):标记确认号是否有效(确认报文段),用于解决丢包问题。
- 标志位 PSH(6bit):提示接收端立即从缓冲区读走数据。
- 标志位 RST(6bit):表示要求对方重新建立连接(复位报文段)。
- 标志位 SYN(6bit):发送/同步标志,用来建立连接,和 ACK 标志位搭配使用。A 请求与 B 建立连接时,SYN=1,ACK=0;B 确认与 A 建立连接时,SYN=1,ACK=1。
- 标志位 FIN(6bit):结束标志,表示关闭⼀个 TCP 连接。
- 窗口(16bit):接收窗口,用于告知发送方该端还能接收多少字节数据,用于解决流控。
- 校验和(16bit):接收端用CRC检验整个报文段有无损坏。
- 源端口、目标端口。
(6)TCP 与 UDP 区别:
- TCP、UDP都是传输层协议。TCP适用于对效率要求相对低,但是对准确性要求高的场景,或是要求有连接的场景。如文件传输、发送邮件等。UDP适用于对效率要求相对高,对准确性要求相对低的场景。如即时通信、直播等。
- TCP首部20字节;UDP的首部只有8个字节。
- TCP有连接、可靠的、面向字节流的;UDP是无连接的、不可靠的、面向报文的。
- TCP有拥塞控制和流量控制,因此传输速度慢;UDP没有较多约束,传输速度快。
- 每⼀条TCP连接只能是点到点的;UDP⽀持⼀对⼀,⼀对多,多对⼀和多对多的交互通信。
- 分片策略不同。TCP 的数据大小如果大于 MSS(最大报文长度) ,则会在传输层进行分片,目标主机收到后,也同样在传输层组装 TCP 数据包,如果中途丢失了⼀个分片,只需要传输丢失的这个分片;UDP 的数据大小如果大于 MTU(最大传输大小)大小,则会在 IP 层进行分片,目标主机收到后,在 IP 层组装完数据,接着再传给传输层。
(7)既然 IP 层会分片,为什么 TCP 层还需要 MSS 呢??
- MTU:⼀个网络包的最大长度,以太网中⼀般为 1500 字节;
- MSS:除去 IP 和 TCP 头部之后,⼀个网络包所能容纳的 TCP 数据的最大长度;
- 如果将 TCP 的整个报文(头部 + 数据)交给 IP 层进行分片:当 IP 层有⼀个超过 MTU 大小的数据(TCP 头部 + TCP 数据)要发送,那么 IP 层就要进行分片,把数据分片成若干片,保证每⼀个分片都小于 MTU。把⼀份 IP 数据报进行分片以后,由目标主机的 IP 层来进行重新组装后,再交给上⼀层TCP 传输层。如果⼀个 IP 分片丢失,整个 IP 报文的所有分片都得重传。因为 IP 层本身没有超时重传机制,它由传输层的 TCP 来负责超时和重传。当接收方发现 TCP 报文(头部 + 数据)的某⼀片丢失后,则不会响应 ACK 给对方,那么发送方的 TCP 在超时后,就会重发「整个 TCP 报文(头部 + 数据)」。因此,可以得知由 IP 层进行分片传输,是非常没有效率的。经过 TCP 层分片后,如果⼀个TCP 分片丢失后,进行重发时也是以 MSS 为单位,而不用重传所有的分片,大大提高了重传的效率。
4.2 TCP 流量控制
(1)流量控制的作用以及实现(详细的介绍见博客《TCP协议》的第7小节):
- 流量控制的目的是控制发送端的发送速度(同时也受拥塞控制的影响),使其按照接收端的数据处理速度来发送数据,避免接收端处理不过来,产生网络拥塞或丢包。
- TCP 实现流量控制的关键是滑动窗口(Sliding Window)。发送端和接收端均有⼀个滑动窗口,对应⼀个缓冲区,记录当前发送或接收到的数据。接收端会在返回的 ACK 报文中包含自己可用于接收数据的缓冲区的大小。
(2)对于发送端来说:
- LastByteAcked 指已发送且收到 ACK 的最后⼀个位置。
- LastByteSent 指向已发送但还未收到 ACK 的最后⼀个位置。
- LastByteWritten 指向上层应用写入但还未发送的最后⼀个位置。
(3)对于接收端来说:
- LastByteRead 指向 TCP 缓冲区中读到的位置。
- NextByteExpected 指向收到连续包的最后⼀个位置。
- LastByteRcvd 指向收到的包的最后⼀个位置。
(4)零窗口:
- 如果接收端处理过慢,那么 window 可能变为 0,这种情况下发送端就不再发送数据了。如何在接收端window 可用的时候通知发送端呢?TCP 使用来 ZWP(Zero Window Probe,零窗口探针)技术。
- 具体是在发送端引入一个计时器,每当收到⼀个零窗口的应答后就启动该计时器。每间隔⼀段时间就主动发送报文,由接收端来 ACK 窗口大小。若接收者持续返回零窗口(一般是 3 次),则有的 TCP 实现会发送 RST 断开连接。
(5)详细的TCP 的滑动窗口的介绍见博客《TCP协议》的第6小节。
4.3 TCP 拥塞控制
(1)拥塞控制的作用(详细的介绍见博客《TCP协议》的第8和第9小节):
- 流量控制是接收端控制的,拥塞控制是发送端控制的。最终都是控制发送端的发送速率。发送端维持⼀个叫做拥塞窗口 cwnd(congestion window)的状态变量。拥塞窗口的大小取决于网络的拥塞程度,并且动态地在变化。
- 为什么要有拥塞控制,不是有流量控制了吗?流量控制是避免「发送方」的数据填满「接收方」的缓存,但是并不知道网络的通畅情况。拥塞控制的目的就是避免「发送方」的数据填满整个网络。
(2)慢启动:
- 连接建立时,设置 cwnd = 1,表示可以传⼀个 MSS 大小的数据。每经过⼀个 RTT,cwnd 会翻倍(指数增长)。当 cwnd >= ssthresh (slow start threshold) 时,进入拥塞避免阶段。
(3)拥塞避免:
- 每经过⼀个 RTT,cwnd = cwnd + 1(线性增长)。
(4)超时重传:
- 如果发送端超时还未收到 ACK 包,就可以认为网络出现了拥塞。这时会把 sshthresh 设为当前拥塞窗口的⼀半,重新开始慢启动过程。
(5)快速重传 / 快速恢复:
- 在接收方,要求每次收到数据都应该对最后⼀个已收到的有序数据进行确认,如果发送方收到重复确认,那么就可以知道下⼀个报文段丢失,此时执行快速重传,立即重传下⼀个报文段。
- 在这种情况下,只是丢失个别报文段,而不是网络拥塞,因此执行快速恢复,令阈值为当前拥塞窗口的⼀半,拥塞窗口大小等于阈值大小,此时进入拥塞避免阶段。
4.4 TCP 三次握手
(1)我们可以使用 tcpdump 抓包分析,Linux使用 netstat -napt 查看 TCP 连接状态。在工作中 tcpdump 只是用来抓取数据包,然后把抓取的数据包保存成 pcap 后缀的文件,接着用Wireshark 工具进行数据包分析。详细的介绍见博客《TCP协议》的5.1小节。
- 第一次握手:客户端请求建立连接,向服务端发送⼀个 同步报文(SYN=1),同时选择⼀个随机数seq = x 作为 初始序列号。发送完成后客户端就进入 SYN_SENT 状态。
- 第二次握手:服务端收到连接请求报⽂后,如果同意建立连接,则向客户端发送 同步确认报文(SYN=1,ACK=1),确认号 为 ack = x + 1,同时选择⼀个随机数 seq = y 作为 初始序列号。发送完毕后,服务器端就进入 SYN_RCV 状态。
- 第三次握手(可携带数据):客户端收到服务端的确认后,向服务端发送⼀个 确认报文(ACK=1),确认号 为 ack = y + 1,序列号 为 seq = x + 1
- 这时就完成了三次握手,连接建立成功。随后,客户端和服务端的序列号将分别从 x+2 和 y+1 开始进行传输。
(2)TCP三次握手通俗比喻:
- 在二十年前的农村,电话没有普及,手机就更不用说了,所以,通信基本靠吼。
- 老张和老王是邻居,这天老张下地了,结果家里有事,热心的邻居老王赶紧跑到村口,开始叫唤老王。
- 老王:老张唉!我是老王,你能听到吗?
- 老张一听,是老王的声音:老王老王,我是老张,我能听到,你能听到吗?
- 老王一听,嗯,没错,是老张:老张,我听到了,我有事要跟你说。
- “你老婆要生了,赶紧回家吧!”
- 老张风风火火地赶回家,老婆顺利地生了个带把的大胖小子。握手的故事充满了幸福和美满。
(3)为什么需要三次握手,而不是两次或四次??
- 最主要原因是防止「历史连接」初始化了连接。第三次握手可以避免历史连接的影响,而从及时终止历史连接。而两次握手无法解决历史连接问题。
- 避免资源浪费。如果只有「两次握手」,当客户端的 SYN 请求连接在网络中阻塞,客户端没有接收到 ACK 报文,就会重新发送 SYN ,由于没有第三次握手,服务器不清楚客户端是否收到了自己发送的建立连接的 ACK 确认信号,所以每收到⼀个 SYN 就只能先主动建立⼀个连接,如果客户端的 SYN 阻塞了,重复发送多次 SYN 报文,那么服务器在收到请求后就会建立多个冗余的无效链接,造成不必要的资源浪费。
- 还有一种情况是已经失效的客户端发出的请求信息,由于某种原因传输到了服务器端,服务器端以为是客户端发出的有效请求,接收后产生错误。
- 四次握手其实也能够可靠的同步双方的初始化序号,但可以优化成⼀步,所以就成了「三次握手」。而两次握手只保证了一方的初始序列号能被对方成功接收,没办法保证双方的初始序列号都能被确认接收。
(4)三次握手中每一次没收到报文会发生什么情况?
-
第一次握手服务端未收到SYN报文:
- 服务端不会进行任何的动作,而客户端由于一段时间内没有收到服务端发来的确认报文,等待一段时间后会重新发送SYN报文,如果仍然没有回应,会重复这个过程,直到发送次数超过最大重传次数限制,就会返回连接建立失败。
-
第二次握手客户端未收到服务端响应的ACK报文:
- 客户端会继续重传,直到次数限制;而服务端此时会阻塞在accept()处,等待客户端发送ACK报文
-
第三次握手服务端为收到客户端发送过来的ACK报文
- 服务端同样会采用类似客户端的超时重传机制,如果重试次数超过限制,则accept()调用返回-1,服务端建立连接失败;而此时客户端认为自己已经建立连接成功,因此开始向服务端发送数据,但是服务端的accept()系统调用已经返回,此时不在监听状态,因此服务端接收到客户端发送来的数据时会发送RST报文给客户端,消除客户端单方面建立连接的状态。
(5)第二次握手传回了 ACK,为什么还要传回 SYN?
- ACK是为了告诉客户端传来的数据已经接收无误。
- 而传回SYN是为了告诉客户端,服务端响应的确实是客户端发送的报文。
(6)第3次握手可以携带数据吗?
- 第3次握手是可以携带数据的。
- 此时客户端已经处于ESTABLISHED状态。对于客户端来说,它已经建立连接成功,并且确认服务端的接收和发送能力是正常的。
- 第一次握手不能携带数据是出于安全的考虑,因为如果允许携带数据,攻击者每次在SYN报文中携带大量数据,就会导致服务端消耗更多的时间和空间去处理这些报文,会造成CPU和内存的消耗。
(7)为什么每次建立 TCP 连接时,初始化的序列号都要求不⼀样呢?
- 主要为了防止历史报文被下⼀个相同四元组的连接接收;
- 为了安全性,防止黑客伪造的相同序列号的 TCP 报文被对方接收;
(8)SYN 报文被丢弃的两种场景:
- 开启 tcp_tw_recycle 参数,并且在 NAT 网络环境下,造成 SYN 报文被丢弃。如果开启了recycle 和 timestamps 选项,就会开启⼀种叫 per-host 的 PAWS 机制。per-host 是对「对端IP 做 序列号回绕(PAWS)检查」,而非对「IP + 端口」四元组做 PAWS 检查。但是如果客户端网络环境是⽤了 NAT 网关,那么客户端环境的每⼀台机器通过 NAT 网关后,都会是相同的 IP 地址,在服务端看来,就好像只是在跟⼀个客户端打交道⼀样,无法区分出来。Per-host PAWS 机制利用TCP option里的 timestamp 字段的增长来判断干扰数据,而 timestamp 是根据客户端各自的 CPU tick 得出的值。当客户端 A 通过 NAT 网关和服务器建立 TCP 连接,然后服务器主动关闭并且快速回收 TIME-WAIT 状态的连接后,客户端 B 也通过 NAT ⽹关和服务器建立 TCP 连接,注意客户端 A 和 客户端 B 因为经过相同的 NAT 网关,所以是用相同的 IP 地址与服务端建立TCP 连接,如果客户端 B 的 timestamp 比 客户端 A 的 timestamp 小,那么由于服务端的 perhost 的 PAWS 机制的作用,服务端就会丢弃客户端主机 B 发来的 SYN 包。
- TCP 两个队列满了(半连接队列和全连接队列),造成 SYN 报文被丢弃。若开启tcp_syncookies 参数则可在半连接队列满的情况下继续建立连接,前提是全连接队列不满。而当全连接队列满了则会丢弃 SYN 报文。
(9)在没有开启 TCP keepalive,且双方⼀直没有数据交互的情况下,如果客户端的「主机崩溃」了,会发生什么;那「进程崩溃」的情况呢?
- 客户端主机崩溃了,服务端是无法感知到的,在加上服务端没有开启 TCP keepalive,又没有数据交互的情况下,服务端的 TCP 连接将会⼀直处于 ESTABLISHED 连接状态,直到服务端重启进程。所以,我们可以得知⼀个点,在没有使用 TCP 保活机制且双方不传输数据的情况下,一方的TCP 连接处在 ESTABLISHED 状态,并不代表另一方的连接⼀定正常。
- 使用 kill -9 来模拟进程崩溃的情况,发现在 kill 掉进程后,服务端会发送 FIN 报文,与客户端进行四次挥手。所以,即使没有开启 TCP keepalive,且双方也没有数据交互的情况下,如果其中一方的进程发生了崩溃,这个过程操作系统是可以感知的到的,于是就会发送 FIN 报文给对方,然后与对方进行 TCP 四次挥手。
(10)什么是 SYN 攻击?如何防范?
- SYN 攻击属于 DOS 攻击的⼀种,它利用 TCP 协议缺陷,通过发送大量的半连接请求,耗费 CPU 和内存资源。
- 原理:在三次握手过程中,服务器发送 [SYN/ACK] 包(第⼆个包)之后、收到客户端的 [ACK] 包(第三个包)之前的 TCP 连接称为半连接(half-open connect),此时服务器处于 SYN_RECV(等待客户端响应)状态。如果接收到客户端的 [ACK],则 TCP 连接成功,如果未接受到,则会不断重发请求直至成功。SYN 攻击的攻击者在短时间内伪造大量不存在的 IP 地址,向服务器不断地发送 [SYN] 包,服务器回复 [SYN/ACK] 包,并等待客户的确认。由于源地址是不存在的,服务器需要不断的重发直至超时。这些伪造的 [SYN] 包将长时间占用未连接队列,影响了正常的 SYN,导致目标系统运行缓慢、网络堵塞甚至系统瘫痪。
- 检测:当在服务器上看到大量的半连接状态时,特别是源 IP 地址是随机的,基本上可以断定这是⼀次SYN 攻击。
- 防范:主要有两大类,⼀类是通过防火墙、路由器等过滤网关防护,另⼀类是通过加固 TCP/IP 协议栈防范,如增加最大半连接队列、开启tcp_syncookies功能、减少SYN+ACK重传次数。但 SYN 攻击不能完全被阻止,除非将 TCP 协议重新设计,否则只能尽可能的减轻 SYN 攻击的危害。
4.5 TCP 四次挥手
(1)四次挥手图解如下(详细的介绍见博客《TCP协议》的5.2小节):
- 序列号 = 收到报文确认号;确认号 = 收到报文序列号 + 1。
- 第一次挥手:客户端向服务端发送 连接释放报文(FIN=1,ACK=1),主动关闭连接,同时等待服务端的确认。
- 序列号 seq = m, 即客户端上次发送的报文的最后⼀个字节的序号 + 1。
- 确认号 ack = n, 即服务端上次发送的报文的最后⼀个字节的序号 + 1。
- 第⼆次挥手:服务端收到连接释放报文后,立即发出 确认报文(ACK=1),序列号 seq = n,确认号ack = m + 1。这时 TCP 连接处于半关闭状态,这表示客户端已经没有数据发送了,但是服务端可能还要给客户端发送数据。
- 第三次挥手:服务端向客户端发送 连接释放报文(FIN=1,ACK=1),主动关闭连接,同时等待客户端的确认。
- 序列号 seq = p,即服务端上次发送的报⽂的最后⼀个字节的序号 + 1。此时处于半连接状态,若服务端⽆数据发送,则 p == n + 1。
- 确认号 ack = m + 1,与第⼆次挥手相同,因为这段时间客户端没有发送数据。
- 第四次挥手:客户端收到服务端的连接释放报文后,立即发出 确认报文(ACK=1),序列号 seq = m + 1,确认号为 ack = p + 1。此时,客户端就进入了 TIME-WAIT 状态。注意此时客户端的 TCP 连接还没有释放,必须经过2*MSL(最长报文段寿命)的时间后,才进入 CLOSED 状态。而服务端只要收
到客户端发出的确认,就立即进⼊ CLOSED 状态。
(2)为什么需要四次挥手??
- TCP 是全双工的,一方关闭连接后,另一方还可以继续发送数据。所以四次挥手,将断开连接分成两个独立的过程。
- 第三次挥手前可能还要数据进行向请求关闭方发送。
(3)服务端大量 CLOSE-WAIT 的原因是什么??
- 在收到客户端关闭连接以及服务器关闭连接之间,业务代码处理耗时较多造成的。可启动异步处理后续程序避免大量 CLOSE-WAIT 状态。
(4)客户端 TIME_WAIT 过多有什么危害??
- 内存资源占用,比如文件描述符、内存资源、CPU 资源、线程资源等。;
- 对端口资源的占用,⼀个 TCP 连接至少消耗「发起连接方」的⼀个本地端口;
(5)客户端 TIME-WAIT 状态为什么必须等待 2MSL 原因??
- 确保 ACK 报文能够到达服务端,从而使服务端正常关闭连接。第四次挥手时,客户端第四次挥手的 ACK 报文不⼀定会到达服务端。服务端会超时重传 FIN/ACK 报文,此时如果客户端已经断开了连接,那么就无法响应服务端的⼆次请求,这样服务端迟迟收不到 FIN/ACK 报文的确认,就无法正常断开连接。MSL 是报文段在网络上存活的最长时间,客户端等待 2MSL 时间,即「客户端ACK 报文 1MSL 超时 + 服务端 FIN 报文 1MSL 传输」,就能够收到服务端重传的 FIN/ACK 报文,然后客户端重传⼀次 ACK 报文,并重新启动 2MSL 计时器。如此保证服务端能够正常关闭。
- 防止已失效的连接请求报文段出现在之后的连接中。TCP 要求在 2MSL 内不使用相同的序列号,客户端在发送完最后⼀个 ACK 报文段后,再经过时间 2MSL,就可以保证本连接持续的时间内产生的所有报文段都从网络中消失。这样就可以使下⼀个连接中不会出现这种旧的连接请求报文段。或者即使收到这些过时的报文,也可以不处理它。
(6)SO_REUSEADDR 和 SO_REUSEPORT 问题:
- SO_REUSEADDR:
- 解决 server 重启的问题(解决TIME_WAIT 状态过多的问题):server 端调用 close,client 还没有调用 close,则 server 端 socket处于 FIN_WAIT2 状态,持续时间60s,此时 server 重启会失败,在bind时会报错 Address already in use。或者 server 端先调用 close,client 后调用close,则 server 会处于 TIME_WAIT 状态,持续时间也是60s,此时 server 重启会失败,在bind时也会报错 Address already in use。解决方法:套接字bind前设置SO_REUSEADDR,或者 SO_REUSEPORT;
- 解决 ip 为零的通配符问题:例如: socketA 绑定了0.0.0.0:2222,socketB 绑定10.164.129.22:2222时,或者相反情况,都会报错 Address already in use。因为 0.0.0.0 相当于通配符,可以匹配到10.164.129.22,在没有设置地址复用或者端口复用前就会有此问题。解决方法:方案1:socketA 和 socketB 在 bind 前设置 SO_REUSEADDR, 并且 socketB 必须在socketA 调用 listen 前调用 bind。方案2:socketA 和 socketB 在 bind 前均设置了SO_REUSEPORT。⽅案3: socketB 在调⽤ bind 前设置进行强制bind,而不用管 socketA 是什么状态。
- SO_REUSEPORT:支持多个进程或者线程绑定到同⼀端口,提高服务器程序的性能。可以在调用bind 绑定端口号之前进行设置。
- 允许多个套接字 bind()/listen() 同⼀个TCP/UDP 端口:每⼀个线程拥有自己的服务器套接字,在服务器套接字上没有了锁的竞争;
- 内核层面实现负载均衡(“惊群”的解决方法之⼀);
- 安全层面,监听同⼀个端口的套接字只能位于同一个用户下面。
4.6 TCP 粘包问题
(1)粘包的原因(详细的介绍见博客《TCP协议》的第12小节):
- TCP 的数据块是没有边界、没有结构的字节流,因此可能产生粘包:发送方为了将多个发往接收端的包更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小、数据量小的数据包,合并成一个大的数据包⼀次性发送。接收方不能及时读取数据,导致缓冲区中的多个包粘连。
(2)解决方法:
- 发送方关闭 Nagle 算法(使用 TCP_NODELAY 可以禁用Nagle算法)。
- 应用层定义消息边界,最常见的两种解决方案就是基于长度或者基于终结符:
- 基于长度的实现有两种方式,⼀种是使用固定长度;另⼀种方式是使用不固定长度,但是需要在应用层协议的协议头中增加表示负载长度的字段,HTTP 协议的消息边界就是基于长度实现的;
- HTTP 协议除了使用基于长度的方式实现边界,也会使用基于终结符的策略,当 HTTP 使用块传输机制时,HTTP 头中就不再包含 Content-Length 了,它会使用负载大小为 0 的 HTTP 消息作为终结符表示消息的边界。
- 基于特定的规则实现消息的边界,例如:使用 TCP 协议发送 JSON 数据,接收方可以根据接收到的数据是否能够被解析成合法的 JSON 判断消息是否终结。
(3)为什么 UDP 协议没有粘包问题?
- UDP 是面向报文的,应用层交给 UDP 多长的报文,UDP 就照样发送,既不合并,也不拆分,而是保留这些报文的边界。
4.7 TCP Socket交互流程
(1)交互流程图如下(详细的介绍流程见博客《网络编程套接字》):
(2)服务器:
- 创建socket
int socket(int domain, int type, int protocol);
- 参数解析:
- domain:协议域,决定了socket的地址类型,IPv4为AF_INET。
- type:指定socket类型,SOCK_STREAM为TCP连接。
- protocol:指定协议。IPPROTO_TCP表示TCP协议,为0表示默认协议。
- 绑定socket和端口号
int bind(int sockfd, const struct sockaddr* addr, socklen_t addrlen);
- 参数解析:
- sockfd:socket返回的套接字描述符,类似于文件描述符。
- addr:有个sockaddr类型数据的指针,指向的是被绑定结构变量。
- addrlen:地址长度。
// IPv4的sockaddr地址结构
struct sockaddr_in
{sa_family_t sin_family; // 协议类型,AF_INETin_port_t sin_port; // 端⼝号struct in_addr sin_addr; // IP地址
};struct in_addr
{uint32_t s_addr;
}
- 监听端口号
int listen(int sockfd, int backlog);
- 参数解析:
- sockfd:要监听的sock描述字。
- backlog:accept队列(将要建立连接的队列)长度=min(somaxconn, backlog),其中somaxconn是内核参数。
- 接收用户请求(三次握手完成后)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
- 参数解析:
- sockfd:服务器socket描述字。
- addr:指向地址结构指针。
- addrlen:协议地址长度。
- 从socket中读取字符
size_t read(int fd, void *buf, size_t count);
- 参数解析:
- fd:连接描述字。
- buf:缓冲区。
- count:缓冲区长度。
- 关闭socket
int close(int fd);
- 参数解析:
- fd:accept返回的连接描述字,每个连接有⼀个。而sockfd是监听描述字,⼀个服务器只有⼀个,用于监听是否有连接。
(3)客户机:
- 创建socket
int socket(int domain, int type, int protocol);
- 连接指定计算机**(第二次握手完成后)**
int connect(int sockfd, struct sockaddr *addr, socklen_t addrlen);
- 参数解析:
- sockfd:客户端的sock描述字。
- addr:服务器地址。
- addrlen:socket地址长度。
- 向socket写入信息
size_t write(int fd, const void *bud, size_t count);
- 关闭socket
int close(int fd)
(4)close 与 shutdown的区别:
- close 关闭本进程的 socket id ,但链接还是开着的(根据计数值决定是否关闭),用这个 socket id的其他进程还能用这个链接,能读/写这个 socket id;
- shutdown 则破坏了 socket 链接,读的时候可能检测到EOF结束符,写的时候可能会收到一个信号,这个信号可能直到 socket 缓冲区被填充了才收到,其次还有关闭链接类型的参数,0 不能再读,1 不能再写,2 读写都不能
4.8 UDP 协议以及和 TCP 协议的不同
(1)UDP 协议的报文格式(详细的介绍见博客《UDP协议》):
- 首部字段只有 8 个字节,包括源端口、目的端口、长度、校验和。UDP详细的介绍见博客《UDP协议》。
(2)TCP 和 UDP 的区别?
- 最根本区别:TCP 是面向连接,而 UDP 是无连接。
- 可以这么形容:TCP是打电话,UDP是大喇叭。
(3)TCP和UDP的应用场景?
- TCP应用场景: 效率要求相对低,但对准确性要求相对高的场景。因为传输中需要对数据确认、重发、排序等操作,相比之下效率没有UDP高。例如:文件传输(准确高要求高、但是速度可以相对慢)、收发邮件、远程登录。
- UDP应用场景: 效率要求相对高,对准确性要求相对低的场景。例如:QQ聊天、在线视频、网络语音电话(即时通讯,速度要求高,但是出现偶尔断续不是太大问题,并且此处完全不可以使用重发机制)、广播通信(广播、多播)。
(4)为什么QQ采用UDP协议?
- 首先,QQ并不是完全基于UDP实现。比如在使用QQ进行文件传输等活动的时候,就会使用TCP作为可靠传输的保证。
- 使用UDP进行交互通信的好处在于,延迟较短,对数据丢失的处理比较简单。同时,TCP是一个全双工协议,需要建立连接,所以网络开销也会相对大。
- 如果使用QQ语音和QQ视频的话,UDP的优势就更为突出了,首先延迟较小。最重要的一点是不可靠传输,这意味着如果数据丢失的话,不会有重传。因为用户一般来说可以接受图像稍微模糊一点,声音稍微不清晰一点,但是如果在几秒钟以后再出现之前丢失的画面和声音,这恐怕是很难接受的。
- 由于QQ的服务器设计容量是海量级的应用,一台服务器要同时容纳十几万的并发连接,因此服务器端只有采用UDP协议与客户端进行通讯才能保证这种超大规模的服务
- 简单总结一下:UDP协议是无连接方式的协议,它的效率高,速度快,占资源少,对服务器的压力比较小。但是其传输机制为不可靠传送,必须依靠辅助的算法来完成传输控制。QQ采用的通信协议以UDP为主,辅以TCP协议。
(5)UDP协议为什么不可靠?
- UDP在传输数据之前不需要先建立连接,远地主机的运输层在接收到UDP报文后,不需要确认,提供不可靠交付。总结就以下四点:
- 不保证消息交付:不确认,不重传,无超时
- 不保证交付顺序:不设置包序号,不重排,不会发生队首阻塞
- 不跟踪连接状态:不必建立连接或重启状态机
- 不进行拥塞控制:不内置客户端或网络反馈机制
(6)DNS为什么要用UDP?
- 更准确地说,DNS既使用TCP又使用UDP。
- 当进行区域传送(主域名服务器向辅助域名服务器传送变化的那部分数据)时会使用TCP,因为数据同步传送的数据量比一个请求和应答的数据量要多,而TCP允许的报文长度更长,因此为了保证数据的正确性,会使用基于可靠连接的TCP。
- 当客户端想DNS服务器查询域名(域名解析)的时候,一般返回的内容不会超过UDP报文的最大长度,即512字节,用UDP传输时,不需要创建连接,从而大大提高了响应速度,但这要求域名解析服务器和域名服务器都必须自己处理超时和重传从而保证可靠性。
5. HTTP协议
- HTTP 是超文本传输协议,是⼀个在计算机世界里专门在「两点」之间「传输」文字、图片、音频、视频等「超文本」数据的「约定和规范」详细的介绍见博客《HTTP协议》。
5.1 HTTP 请求方法以及过程和原理
(1)HTTP请求方法如下(详细的介绍见博客《HTTP协议》的第3小节):
- GET:获取服务器的指定资源。
- HEAD:与 GET 方法⼀样,都是发出⼀个获取服务器指定资源的请求,但服务器只会返回 Header而不会返回 Body。用于确认 URI 的有效性及资源更新的日期时间等。⼀个典型应用是下载文件时,先通过 HEAD 方法获取 Header,从中读取文件大小 Content-Length;然后再配合 Range字段,分片下载服务器资源。
- POST:提交资源到服务器 / 在服务器新建资源。
- PUT:替换整个目标资源。
- PATCH:替换目标资源的部分内容。
- DELETE:删除指定的资源。
- OPTIONS:可以检测服务器支持哪些 HTTP 方法。
- TRACE:执行⼀个消息环回测试,返回到服务端的路径。客户端请求连接到目标服务器时可能会通过代理中转,通过 TRACE 方法可以查询发送出去的请求的⼀系列操作。
(2)幂等的:一个 HTTP 方法是幂等的。幂等性(Idempotence) 是指某个操作(如请求或方法)无论执行一次还是多次,对系统状态产生的影响是相同的。简单来说,重复执行幂等操作不会导致意外的副作用。
- 常见的幂等方法:GET,HEAD,PUT,DELETE,OPTIONS。
- 常见的非幂等方法:POST。
(3)安全的:⼀个 HTTP 方法是安全的,指这是⼀个对服务器只读操作的方法,不会修改服务器数据。
- 常见的安全方法:GET,HEAD,OPTIONS
- 常见的不安全方法:PUT,DELETE,POST
- 所有安全的方法都是幂等的;有些不安全的方法如 DELETE 是幂等的,有些不安全的方法如 PUT 和 DELETE 则不是。
(4)可缓存的:GET、HEAD。
(5)GET 和 POST 区别:
GET | POST | |
---|---|---|
作用 | 获取服务器资源,可被缓存 | 添加 / 修改服务器资源,不能被缓存 |
幂等 / 安全性 | 幂等,安全(不会改变服务器上的资源) | 非幂等,不安全(会对服务器资源进行改变) |
参数位置 | 明文暴露在URL链接中 | 消息体中 |
参数长度 | 2KB(HTTP本身无限制,浏览器限制) | 无限制 |
(5)HTTP 请求的过程与原理??
- HTTP协议定义了浏览器怎么向服务器请求文档,以及服务器怎么把文档传给浏览器。
- 每个服务器都有一个进程,它不断监听TCP的端口80,以便发现是否有浏览器向它发出连接建立请求。
- 监听到连接请求,就会建立TCP连接。
- 浏览器向服务器发出浏览某个页面的请求,服务器接着就返回所请求的页面作为响应。
- 最后,释放TCP连接。
在浏览器和服务器之间的请求和响应的交互,必须按照规定的格式和遵循一定的规则,这些格式和规则就是超文本传输协议HTTP。
注意:这道题和上面浏览器输入网址发生了什么那道题大差不差。
5.2 HTTP 状态码
(1)信息响应(100–199):
- 100 Continue:表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应成功响应(200–299)
- 200 OK
- 204 No Content:该请求已成功处理,但响应头没有 body 数据。通常用于只需要从客户端往服务器发送信息,而不需要返回数据时
- 206 Partial Content:是应用于 HTTP 分块下载或断点续传,表示响应返回的 body 数据并不是资源的全部,而是其中的⼀部分,也是服务器处理成功的状态。
(2)重定向(300–399):
- 301 Moved Permanently:永久性重定向。说明请求的资源已经不存在了,需改用新的 URL 再次访问。
- 302 Found:临时性重定向,说明请求的资源还在,但暂时需要用另⼀个 URL 来访问。常见应用场景是通过 302 跳转将所有的 HTTP 流量重定向到 HTTPS。
- 304 Not Modified:响应不包含消息体。不具有跳转的含义,表示资源未修改,重定向已存在的缓冲文件,也称缓存重定向,也就是告诉客户端可以继续使用缓存资源,用于缓存控制。
(3)客户端错误(400–499):
- 400 Bad Request:请求报文中存在语法错误,或者参数有误。
- 403 Forbidden:表示服务器禁止访问资源,并不是客户端的请求出错。
- 404 Not Found:表示请求的资源在服务器上不存在或未找到,所以无法提供给客户端。
(4)服务器错误 (500–599):
- 500 Internal Server Error:发生不可预知的错误。
- 501 Not Implemented:表示客户端请求的功能还不支持,类似“即将开业,敬请期待”的意思。
- 502 Bad Gateway:通常是服务器作为网关或代理时返回的错误码,表示服务器自身工作正常,访问后端服务器发生了错误。
- 503 Service Unavailable:表示服务器当前很忙,暂时无法响应客户端,类似“网络服务正忙,请稍后重试”的意思。
(5)301、302重定向的原理:返回的 Header 中有⼀个 Location 字段指向目标 URL,浏览器会重定向到这个 URL。
5.3 HTTP 缓存
(1)浏览器可以将已经请求过的资源(如图片、JS 文件)缓存下来,下次再次请求相同的资源时,直接从缓存读取。浏览器采用的缓存策略有两种:强制缓存、协商缓存。浏览器根据第⼀次请求资源时返回的
- HTTP 响应头来选择缓存策略。强制缓存优先级大于协商缓存。
(2)强制缓存:
-
强缓存是利用 HTTP 响应头部字段实现的,它们都用来表示资源在客户端缓存的有效期:
- Cache-Control, 是⼀个相对时间;Cache-Control的优先级高于 Expires 。
- Expires,是⼀个绝对时间;
-
具体的实现流程如下:
- 当浏览器第⼀次请求访问服务器资源时,服务器会在返回这个资源的同时,在响应头部加上Cache-Control 字段,其中设置了过期时间;
- 浏览器再次请求访问服务器中的该资源时,会先通过请求资源的时间与 Cache-Control 中设置的过期时间来计算出该资源是否过期,如果没有,则使⽤该缓存,否则重新请求服务器;
- 服务器再次收到请求后,会更新响应头部的 Cache-Control。
(3)协商缓存:协商缓存可以基于两种头部来实现。
- 第⼀种:请求头部中的 If-Modified-Since 字段与响应头部中的 Last-Modified 字段实现。响应头部中的 Last-Modified 标示这个响应资源的最后修改时间;请求头部中的 If-Modified-Since表示当资源过期时,发现响应头中具有 Last-Modified 声明,则再次发起请求的时候带上 LastModified 的时间,服务器收到请求后发现有 If-Modified-Since 则与被请求资源的最后修改时间进行对比,如果最后修改时间较新(大),说明资源又被改过,则返回最新资源,HTTP 200 OK;如果最后修改时间较旧(小),说明资源无修改,响应 HTTP 304 走缓存。
- 第⼆种:请求头部中的 If-None-Match 字段与响应头部中的 ETag 字段(唯⼀标识响应资源)。其中请求头部中的 If-None-Match 表示当资源过期时,浏览器发现响应头里有 Etag,则再次向服务器发起请求时,会将请求头If-None-Match 值设置为 Etag 的值。服务器收到请求后进行对对,如果资源没有变化返回 304,如果资源变化了返回 200。
(4)第⼀种实现方式是基于时间实现的,第⼆种实现方式是基于⼀个唯⼀标识实现的,相对来说后者可以更加准确地判断文件内容是否被修改,避免由于时间篡改导致的不可靠问题。
- 注意,只有在未能命中强制缓存的时候,才能发起带有协商缓存字段的请求。
5.4 HTTP 报文格式
(1)请求报文的格式如下(详细的介绍见博客《HTTP协议》)。
- HTTP 协议以 ASCII 码传输,请求报文由请求行、请求头、(空行以及)消息体组成。⼀个消息主体⼀定包含⼀个实体主体,通常情况下消息主体等于实体主体,实体主体也可能经过传输编码机制处理,在通信时按某种编码方式传输。
(2)响应报文如下:
- HTTP 响应报文也由三部分组成:状态行、响应头、(空行以及)消息体。
(3)HTTP 分块传输编码:
- 在 HTTP 通信过程中,请求的编码实体资源尚未全部传输完成之前,浏览器无法显示请求页面。在传输大容量数据时,通过把数据分割成多块,能够让浏览器逐步显示页面。这种把实体主体分块的功能称为分块传输编码(Chunked Transfer Coding)。
- 它通过在 Header 里两个参数实现的,客户端发请求时对应的是 Range ,服务器端响应时对应的是 Content-Range。Range 用于请求头中,指定第⼀个字节的位置和最后⼀个字节的位置。Content-Range 用于响应头中,在发出带 Range 的请求后,服务器会在 Content-Range 头部返回当前接受的范围和文件总大小。
(4)HTTP 常见字段:
- Host 字段:客户端指定服务器的域名,可以将请求发往「同⼀台」服务器上的不同网站。
- Content-Length 字段:服务器返回数据的长度。
- Content-Type 字段:服务器回应客户端的数据格式。客户端请求的时候,可以使用 Accept 字段声明自己可以接受哪些数据格式。
- Content-Encoding 字段:服务器返回数据使用的压缩格式。客户端在请求时,用 AcceptEncoding 字段说明自己可以接受哪些压缩方法。
- Connection 字段:最常用于客户端要求服务器使用 TCP 持久连接,以便其他请求复用。
HTTP/1.1 版本的默认连接都是持久连接,但为了兼容老版本的 HTTP,需要指定 Connection 首部字段的值为 Keep-Alive。
5.5 Cookie 和 Session 区别
(1)二者都是用来跟踪浏览器用户身份的会话方式(详细的介绍见博客《HTTP协议》的第5小节)。
- Cookie:存在浏览器里,可以设置过期时间。每次访问服务器时,浏览器会自动在 header 中携带cookie。如果浏览器禁用了 cookie,可以使用 URL 地址重写机制,将信息保存在 URL 里。
- Session:存在服务端,由服务器维护,服务端设置过期时间。如果用户长时间不和服务器交互(比如30 分钟),那么 session 就会被销毁,交互则会刷新 session。浏览器的 cookie 中只保存⼀个sessionId,所有其他信息均保存在服务端,由 sessionId 标识。
5.6 Session 的实现原理
(1)图解过程如下:
- Manager 充当⼀个 session 管理器的角色,主要存储⼀些配置信息,比如 session 的存活时间,cookie 的名字等等。而所有的 session 存在 Manager 内部的⼀个 Provider 中。所以 Manager 会把sid(sessionID)传递给 Provider,让它去找这个 ID 对应的具体是哪个 session。
- Provider 就是⼀个容器,最常见的应该就是⼀个散列表,将每个 sid 和对应的 session ⼀⼀映射起来。收到 Manager 传递的 sid 之后,它就找到 sid 对应的 session 结构,也就是 Session 结构,然后返回它。
- Session 中存储着用户的具体信息,由 Handler 函数中的逻辑拿出这些信息,生成该用户的 HTML 网页,返回给客户端。
(2)既然 session 就是键值对,为啥不直接用哈希表??
- 可以存储⼀些辅助数据,比如 sid,访问次数,过期时间或者最后一次的访问时间,这样便于实现像 LRU、LFU 这样的算法。
- 可以有不同的存储方式,比如存入缓存数据库 Redis,或者存入 MySQL 等等。如果用编程语言内置的哈希表,那么 session 数据就是存储在内存中,如果数据量大,很容易造成程序崩溃,而且一旦程序结束,所有 session 数据都会丢失。
(3)Provider 为啥要抽象出来??
- 上图的 Provider 就是⼀个散列表,保存 sid 到 Session 的映射,但是实际中肯定会更加复杂。我们不是要时不时删除⼀些 session 吗,除了设置存活时间之外,还可以采用⼀些其他策略,比如 LRU 缓存淘汰算法,这样就需要 Provider 内部使用哈希链表这种数据结构来存储 session。
(4)Manager 为啥要抽象出来??
- 大部分具体工作都委托给 Session 和 Provider 承担了,Manager 主要就是一个参数集合,比如session 的存活时间,清理过期 session 的策略,以及 session 的可用存储方式。Manager 屏蔽了操作的具体细节,我们可以通过 Manager 灵活地配置 session 机制。
5.7 HTTP/1.1
(1)HTTP/1.1图解如下:
- 优点:简单、灵活和易于扩展、应用广泛和跨平台。
- 缺点:无状态、明文传输、不安全。
(2)HTTP/1.1 相比 HTTP/1.0 性能上的改进:
- 使用长连接的方式改善了 HTTP/1.0 短连接造成的性能开销,不过长连接会占用服务器的资源。
- 支持管道(pipeline)网络传输,只要第⼀个请求发出去了,不必等其回来,就可以发第⼆个请求出去,可以减少整体的响应时间。
(3)性能瓶颈:
- 请求 / 响应头部 未经压缩就发送,首部信息越多延迟越大,且每次互相发送相同的首部造成的浪费较多;
- 服务器是按请求的顺序响应的,如果服务器响应慢,会导致客户端⼀直请求不到数据,也就是队头阻塞;
- 没有请求优先级控制;
- 请求只能从客户端开始,服务器只能被动响应。
(4)如何优化?
- 尽量避免发送 HTTP 请求:尽量使用缓存处理。
- 尽量减少请求次数:利用代理服务器等减少重定向请求次数;合并请求资源;延迟发送请求。
- 减少响应的数据大小:通过有损或无损压缩对响应的资源进行压缩。
5.8 HTTP/2.0
(1)HTTP/2.0 改进点 [基于 HTTPS ]:
- Header 压缩:头部的编码通过「静态表(保存常用字段编码并固定在协议中)、动态表(动态添加静态表没有的字段编码)、Huffman 编码」共同完成的。
- 二进制分帧:HTTP/1.x 采用文本格式传输数据。HTTP/2.0 将所有传输信息分割为若干个帧,采用二进制格式进行编码。具体实现上,是在应用层(HTTP)和传输层(TCP)之间增加⼀个⼆进制分帧层。每个请求对应⼀个流,有个唯⼀的标识符。请求报文会被拆分为⼀个或多个帧(帧头+消息负载),每个帧有序列号,以及自己所属流的标识符,接收端自行合并。同时,⼆进制分帧采用的流传输也为多路复用提供了基础。
- 多路复用:每个请求或响应的数据包称为⼀个数据流,每个数据流都有唯⼀的编号,因此不同流的帧是可以乱序发送的(即可以并发不同的流)。因为每个帧的头部会携带流编号信息,所以接收端可以通过流编号有序拼接 HTTP 消息。客户端和服务器双方都可以建立流, 其中客户端建立的流编号必须是奇数号,而服务器建立的流编号必须是偶数号。客户端还可以指定数据流的优先级。
- 服务端推送:服务端根据客户端的请求,提前推送额外的资源给客户端,可以减轻数据传输的冗余步骤,同时加快页面响应速度,提升用户体验。比如在发送页面 HTML 时主动推送其它 CSS/JS资源,而不用等到浏览器解析到相应位置,发起请求再响应。
(2)HTTP/2.0 缺陷:
- HTTP 队头阻塞。HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整且连续的,这样内核才会将缓冲区里的数据返回给 HTTP 应用,那么当「前 1 个字节数据」没有到达时,后收到的字节数据只能存放在内核缓冲区里,只有等到这 1 个字节数据到达时,HTTP/2 应⽤层才能从内核中拿到数据,这就是 HTTP/2 队头阻塞问题。所以,⼀旦发生了丢包现象,就会触发 TCP 的重传机制,这样在⼀个 TCP 连接中的所有的 HTTP 请求都必须等待这个丢了的包被重传回来。
- 慢启动降低效率。TCP 由于具有「拥塞控制」的特性,所以刚建立连接的 TCP 会有个「慢启动」的过程,它会对 TCP 连接产生"减速"效果。
- 网络切换重连。⼀个 TCP 连接是由四元组(源 IP 地址,源端口,目标 IP 地址,目标端口)确定的,这意味着如果 IP 地址或者端口变动了,就会导致需要 TCP 与 TLS 重新握手,这不利于移动设备切换网络的场景,比如 4G 网络环境切换成 WIFI。
5.9 HTTP/1.0,1.1,2.0 的区别?
(1)关键需要记住 HTTP/1.0 默认是短连接,可以强制开启,HTTP/1.1 默认长连接,HTTP/2.0 采用多路复用。
(2)HTTP/1.0:
- 默认使用短连接,每次请求都需要建立一个 TCP 连接。它可以设置Connection: keep-alive 这个字段,强制开启长连接。
(3)HTTP/1.1:
- 引入了持久连接,即 TCP 连接默认不关闭,可以被多个请求复用。
- 分块传输编码,即服务端每产生一块数据,就发送一块,用” 流模式” 取代” 缓存模式”。
- 管道机制,即在同一个 TCP 连接里面,客户端可以同时发送多个请求。
(4)HTTP/2.0:
- 二进制协议,1.1 版本的头信息是文本(ASCII 编码),数据体可以是文本或者二进制;2.0 中,头信息和数据体都是二进制。
- 完全多路复用,在一个连接里,客户端和浏览器都可以同时发送多个请求或回应,而且不用按照顺序一一对应。
- 报头压缩,HTTP 协议不带有状态,每次请求都必须附上所有信息。Http/2.0 引入了头信息压缩机制,使用 gzip 或 compress 压缩后再发送。
- 服务端推送,允许服务器未经请求,主动向客户端发送资源。
5.10 HTTP/3 / QUIC
(1)HTTP/3 优化?
- 改进头部压缩算法。HTTP/3 中的 QPACK 也采用了静态表、动态表及 Huffman 编码。HTTP/2 和 HTTP/3 的动态表编解码方式不同,QUIC 会有两个特殊的单向流,这两个特殊的单向流是用来同步双方的动态表,编码方收到解码方更新确认的通知后,才使用动态表编码 HTTP 头部。
- 更换传输协议。HTTP/2 虽然通过多个请求复用⼀个 TCP 连接解决了 HTTP 的队头阻塞 ,但是⼀旦发生丢包,就会阻塞住所有的 HTTP 请求,这属于 TCP 层队头阻塞。所以 HTTP/3 把 HTTP下层的 TCP 协议改成了 UDP,基于 UDP 的 QUIC 协议 可以实现类似 TCP 的可靠传输。
(2)QUIC 实现了两种级别的流量控制,分别为 Stream 和 Connection 两种级别:
- Stream 流量控制:每个 HTTP 请求对应⼀个流,每个 Stream 都有独立的滑动窗口,所以每个Stream 都可以做流量控制,防止单个 Stream 占用连接的全部接收缓冲。
- Connection 流量控制:限制连接中所有 Stream 加起来的总字节数,防止发送方超过连接的缓冲容量。
(3)QUIC 有以下 3 个特点:
- 无队头阻塞:当某个流发生丢包时,只会阻塞这个流,其他流不会受到影响,因此不存在队头阻塞问题。而 HTTP/2 只要某个流中的数据包丢失了,其他流也会受影响。
- 更快的建立连接:对于 HTTPS 和 HTTP/2 协议,TCP 和 TLS 是分层的,需要分批次来握手,先TCP 握手,再 TLS 握手。HTTP/3 在传输数据前虽然需要 QUIC 协议握手,这个握手过程只需要1 RTT,握手的目的是为确认双方的「连接 ID」,连接迁移就是基于连接 ID 实现的。不过 QUIC协议并不是与 TLS 分层,其内部包含了 TLS,再加上 QUIC 使用的是 TLS/1.3,因此仅需 1 个
RTT 就可以「同时」完成建立连接与密钥协商。 - 连接迁移:基于 TCP 传输协议的 HTTP 协议,由于是通过四元组(源 IP、源端口、目的 IP、目的端口)确定⼀条 TCP 连接,那么当移动设备的网络从 4G 切换到 WIFI 时,意味着 IP 地址变化了,那么就必须要断开连接,然后重新建立连接。而建立连接的过程包含 TCP 三次握手和 TLS 四次握手的时延,以及 TCP 慢启动的减速过程,给用户的感觉就是网络突然卡顿了⼀下,因此连接的迁移成本是很高的。而 QUIC 协议没有用四元组的方式来“绑定”连接,而是通过连接 ID来标记通信的两个端点,客户端和服务器可以各自选择⼀组 ID 来标记自己,因此即使移动设备的网络 IP 地址变化了,只要仍保有上下文信息(比如连接 ID、TLS 密钥等),就可以“无缝”地复用原连接,消除重连的成本,没有卡顿感,达到了连接迁移的功能。
(4)我们拿一张图看一下HTTP协议的变迁:
6. HTTPS
(1)HTTPS保证数据安全:
- 数字签名:发送端将消息使用 hash 函数生成摘要,并使⽤私钥加密后得到“数字签名”,并将其附在消息之后。接收端使用公钥对“数字签名”解密,确认发送端身份,之后对消息使⽤ hash 函数处理并与接收到的摘要对比,确认消息是否被修改。
- 数字证书:数字中心 CA 使用私钥对用户的公钥和相关信息⼀起加密,生成“数字证书”。发送端在发送时除了需要数字签名,还需要附上数字证书。接收端使用 CA 公钥解开数字证书,拿到用户的公钥,则可证明该数字签名是真实发送端发送的。
- 证书吊销列表 (CRL) :⼀个结构化数据文件,该文件包含证书颁发机构 (CA) 已经吊销的证书的序列号及其吊销日期等。
- 证书吊销列表分发点 (CDP) :是含在数字证书中的⼀个可以供各种应用软件自动下载的最新的 CRL 的位置信息。CDP ⼀般是⼀个可以访问 http 网址。
- 证书状态在线查询协议(OCSP):是用于实时查询数字证书在某⼀时间是否有效的标准。
(2)HTTP 与 HTTPS 有哪些区别?
- 安全性:HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 在 TCP 和HTTP 之间加⼊了 SSL/TLS 安全协议,使得报文能够加密传输。
- 连接步骤:TCP 三次握手之后便可进行 HTTP 的报⽂传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
- 速度、资源:根据上述分析,HTTP速度快,使用资源少;HTTPS速度慢,使用资源多。
- 端口号:HTTP 的端口号是 80,HTTPS 的端口号是 443。
- HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。
6.1 SSL/TLS
(1)SSL/TLS协议的基本思路是采用公钥加密法,也就是说,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密。作用如下:
- 所有信息都是加密传播,第三方无法窃听。
- 具有校验机制,⼀旦被篡改,通信双方会立刻发现。
- 配备身份证书,防止身份被冒充。
(2)如何保证公钥不被篡改?
- 解决方法:将公钥放在数字证书中。只要证书是可信的,公钥就是可信的。
(3)公钥加密计算量太大,如何减少耗用的时间?
- 每⼀次对话(session),客户端和服务器端都生成⼀个"对话密钥"(session key),用它来加密信息。由于"对话密钥"是对称加密,所以运算速度非常快,而服务器公钥只用于加密"对话密钥"本身,这样就减少了加密运算的消耗时间。
(4)TCP 与 HTTPS 握手顺序:
- 「HTTPS 是先进行 TCP 三次握手,再进行 TLSv1.2 四次握手」,而「HTTPS 中的 TLS 握手过程可以同时进行三次握手」,这个场景是可能存在的,但是需要同时满足下面这两个条件才可以:
- 客户端和服务端已经完成过⼀次通信;
- TLS 版本是 1.3 (TLSv1.3 会话恢复机制,在重连 TLvS1.3 只需要 0-RTT);
- 客户端和服务端都开启了 TCP Fast Open 功能(第⼀次通信服务端设置cookie选项,之后客户端保存并在后续再次连接时使用,可传递cookie建立连接并传输数据)
6.2 RSA 密钥交换算法
(1)第⼀次握手:客户端发出请求(ClientHello)。首先,客户端(通常是浏览器)先向服务器发出加密通信的请求,这被叫做ClientHello请求。在这⼀
步,客户端主要向服务器提供以下信息。
- 支持的协议版本,比如TLS 1.0版。
- ⼀个客户端⽣成的随机数,稍后⽤于⽣成"对话密钥"。
- 支持的加密方法,比如RSA公钥加密。
- 支持的压缩方法。
(2)第⼆次握手:服务器回应(SeverHello)。服务器收到客户端请求后,向客户端发出回应,这叫做SeverHello。服务器的回应包含以下内容。
- 确认使用的加密通信协议版本。如果浏览器与服务器支持的版本不⼀致,服务器关闭加密通信。
- 服务器生成的随机数,稍后用于生成"对话密钥"。
- 确认使用的加密方法。
- 服务器证书。
除了上面这些信息,如果服务器需要确认客户端的身份,就会再包含⼀项请求,要求客户端提供"客户端证书"。
(3)第三次握手:客户端回应。客户端收到服务器回应以后,首先验证服务器证书。如果证书不是可信机构颁布、或者证书中的域名与实际域名不⼀致、或者证书已经过期,就会向访问者显示⼀个警告,由其选择是否还要继续通信。如果证书没有问题,客户端就会从证书中取出服务器的公钥。然后,向服务器发送下面三项信息。
- ⼀个随机数。该随机数用服务器公钥加密,防止被窃听。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 客户端握手结束通知,表示客户端的握手阶段已经结束。这⼀项同时也是前面发送的所有内容的hash值,用来供服务器校验。
此时客户端和服务器就同时有了三个随机数,接着双方就用事先商定的加密方法,各自生成本次会话所用的同⼀把"会话密钥"。此外,如果前⼀步服务器要求客户端证书,客户端会在这⼀步发送证书及相关信息。
(4)第四次握手:服务器的最后回应。服务器收到客户端的第三个随机数pre-master key之后,计算⽣成本次会话所⽤的"会话密钥"。然后向客户端最后发送下面信息。
- 编码改变通知,表示随后的信息都将用双方商定的加密方法和密钥发送。
- 服务器握手结束通知,表示服务器的握手阶段已经结束。这⼀项同时也是前面发送的所有内容的hash值,用来供客户端校验。
至此,整个握手阶段全部结束。接下来,客户端与服务器进⼊加密通信,就完全是使用普通的HTTP协议,只不过用"会话密钥"加密内容。
(5)如何自动切换到 HTTPS 的?
- 最原始的使用 302 跳转。但这样做有⼀个明显的安全漏洞, 很可能都没到 302 跳转的时候就被劫持了。
- 使⽤ HSTS。支持 HSTS 的服务端,可以强制访问它的浏览器使用 HTTPS 协议。
(6)使用 RSA 密钥协商算法的最大问题是不支持前向保密
- 因为客户端传递随机数(用于生成对称加密密钥的条件之⼀)给服务端时使用的是公钥加密的,服务端收到到后,会用私钥解密得到随机数。所以⼀旦服务端的私钥泄漏了,过去被第三方截获的所有 TLS通讯密文都会被破解。为了解决这个问题,后面就出现了 ECDHE 密钥协商算法,我们现在大多数网站使用的正是 ECDHE 密钥协商算法。
7. DNS
(1)整体流程:浏览器搜索自身的 DNS 缓存、搜索操作系统的 DNS 缓存、读取本地的 Host 文件和向本地 DNS 服务器进行查询等。
(2)假设你要查询 www.baidu.com 的 IP 地址:
- 首先会查找浏览器的缓存,看看是否能找到www.baidu.com对应的IP地址,找到就直接返回;否则进行下一步。
- 将请求发往给本地DNS服务器,如果查找到也直接返回,否则继续进行下一步;
- 本地DNS服务器向根域名服务器发送请求,根域名服务器返回负责com的顶级域名服务器的IP地址的列表。
- 本地DNS服务器再向其中一个负责com的顶级域名服务器发送一个请求,返回负责baidu.com的权限域名服务器的IP地址列表。
- 本地DNS服务器再向其中一个权限域名服务器发送一个请求,返回www.baidu.com所对应的IP地址。
(2)DNS 服务器查询共有两类:
- 递归查询:当 A 向 B 查询某个域名的 IP 地址时,如果 B 不知道被查询的域名的 IP 地址,那么B 会替 A 向更上层的服务器发起查询,将查询结果返回 A。
- 迭代查询:当 A 向 B 查询某个域名的 IP 地址时,如果 B 不知道被查询的域名的 IP 地址,B 会告诉 A 下⼀步应该向哪个服务器查询,由 A 自己去查。
⼀般来说,主机向本地域名服务器的查询是递归查询,而本地域名服务器向根域名服务器的查询是迭代查询。
8. IP协议
(1)IP协议(头部20字节)使用逐跳的方式确定通信路径,为上层协议提供无状态、无连接、不可靠的服务。详细的介绍见博客《IP协议》。
- 无状态 是指 IP 通信双⽅不同步传输数据的状态信息,因此所有IP数据报的发送、传输和接收都是相互独立、没有上下文关系的,这种服务最大的缺点是无法处理乱序和重复的IP数据报。
- 无连接 是指 IP 通信双方都不长久地维持对方的任何信息,上层协议每次发送数据的时候,都必须明确指定对方的IP地址。
- 不可靠 是指 IP 协议不能保证 IP 数据报准确地到达接收端,即使检测到 IP 数据报发送失败,则通知上层协议发送失败,而不会试图重传。
(2)IP 转发处理步骤:
- 检查数据报头部的TTL值,如果等于0则丢弃该数据报;
- 查看数据报头部的严格源路由选择选项。如果该项被设置,则检测数据报的目标IP地址是否是本机的某个IP地址。如果不是,则发送⼀个ICMP源站选路失败报文给发送端。如果有必要,则给源端发送⼀个ICMP重定向报文,以告诉它⼀个更合理的下⼀跳路由器;
- 将TTL值减一;
- 处理IP头部选项。如果有必要,则执⾏IP分⽚操作。
(3)IP协议有哪些作用?
- 寻址和路由:在IP数据报中携带源IP地址和目的IP地址来表示该数据包的源主机和目标主机。IP数据报在传输过程中,每个中间节点(IP网关、路由器)只根据网络地址来进行转发,如果中间节点是路由器,则路由器会根据路由表选择合适的路径。IP协议根据路由选择协议提供的路由信息对IP数据报进行转发,直至目标主机。
- 分段和重组:IP数据报在传输过程中可能会经过不同的网络,在不同的网络中数据报的最大长度限制是不同的,IP协议通过给每个IP数据报分配一个标识符以及分段与组装的相关信息,使得数据报在不同的网络中能够被传输,被分段后的IP数据报可以独立地在网络中进行转发,在达到目标主机后由目标主机完成重组工作,恢复出原来的IP数据报。
(4)传输层协议和网络层协议有什么区别?
- 网络层协议负责提供主机间的逻辑通信;传输层协议负责提供进程间的逻辑通信。
(5)IP 地址有哪些分类?
- 一个IP地址在这鞥个互联网范围内是惟一的,一般可以这么认为,IP 地址 = {<网络号>,<主机号>}。
- 网络号:它标志主机所连接的网络地址表示属于互联网的哪一个网络。
- 主机号:它标志主机地址表示其属于该网络中的哪一台主机。
- IP 地址分为 A,B,C,D,E 五大类:
- A 类地址 (1~126):以 0 开头,网络号占前 8 位,主机号占后面 24 位。
- B 类地址 (128~191):以 10 开头,网络号占前 16 位,主机号占后面 16 位。
- C 类地址 (192~223):以 110 开头,网络号占前 24 位,主机号占后面 8 位。
- D 类地址 (224~239):以 1110 开头,保留为多播地址。
- E 类地址 (240~255):以 1111开头,保留位为将来使用。
(6)域名和 IP 的关系?一个 IP 可以对应多个域名吗?
- IP地址在同一个网络中是惟一的,用来标识每一个网络上的设备,其相当于一个人的身份证号。
- 域名在同一个网络中也是惟一的,就像是一个人的名字、绰号。
- 假如你有多个不用的绰号,你的朋友可以用其中任何一个绰号叫你,但你的身份证号码却是惟一的。但同时你的绰号也可能和别人重复,假如你不在,有人叫你的绰号,其它人可能就答应了。
- 一个域名可以对应多个IP,但这种情况DNS做负载均衡的,在用户访问过程中,一个域名只能对应一个IP。
- 而一个IP却可以对应多个域名,是一对多的关系。
(7)IPV4 地址不够如何解决?
- 我们知道,IP地址有32位,可以标记2的32次方个地址,听起来很多,但是全球的网络设备数量已经远远超过这个数字,所以IPV4地址已经不够用了,那怎么解决呢?
- DHCP:动态主机配置协议,动态分配IP地址,只给接入网络的设备分配IP地址,因此同一个MAC地址的设备,每次接入互联网时,得到的IP地址不一定是相同的,该协议使得空闲的IP地址可以得到充分利用。
- CIDR:无类别域间路由。CIDR消除了传统的A类、B类、C类地址以及划分子网的概念,因而更加有效地分配IPv4的地址空间,但无法从根本上解决地址耗尽的问题。
- NAT:网络地址转换协议,我们知道属于不同局域网的主机可以使用相同的IP地址,从而一定程度上缓解了IP资源枯竭的问题,然而主机在局域网中使用的IP地址是不能在公网中使用的,当局域网主机想要与公网主机进行通信时,NAT方法可以将该主机IP地址转换为全球IP地址。该协议能够有效解决IP地址不足的问题。
- IPv6:作为接替IPv4的下一代互联网协议,其可以实现2的128次方个地址,而这个数量级,即使给地球上每一粒沙子都分配一个IP地址也够用,该协议能够从根本上解决IPv4地址不够用的问题。
(8)说下 ARP 协议的工作过程?
- ARP 协议,Address Resolution Protocol,地址解析协议,它是用于实现 IP 地址到 MAC 地址的映射。
- 首先,每台主机都会在自己的 ARP 缓冲区中建立一个 ARP 列表,以表示 IP 地址和 MAC 地址的对应关系。
- 当源主机需要将一个数据包要发送到目的主机时,会首先检查自己的 ARP 列表,是否存在该 IP 地址对应的 MAC 地址;如果有﹐就直接将数据包发送到这个 MAC 地址;如果没有,就向本地网段发起一个 ARP 请求的广播包,查询此目的主机对应的 MAC 地址。此 ARP 请求的数据包里,包括源主机的 IP 地址、硬件地址、以及目的主机的 IP 地址。
- 网络中所有的主机收到这个 ARP 请求后,会检查数据包中的目的 IP 是否和自己的 IP 地址一致。如果不相同,就会忽略此数据包;如果相同,该主机首先将发送端的 MAC 地址和 IP 地址添加到自己的 ARP 列表中,如果 ARP 表中已经存在该 IP 的信息,则将其覆盖,然后给源主机发送一个 ARP 响应数据包,告诉对方自己是它需要查找的 MAC 地址。
- 源主机收到这个 ARP 响应数据包后,将得到的目的主机的 IP 地址和 MAC 地址添加到自己的 ARP 列表中,并利用此信息开始数据的传输。如果源主机一直没有收到 ARP 响应数据包,表示 ARP 查询失败。
(9)为什么既有IP地址,又有MAC 地址?MAC地址和IP地址都有什么作用?
- MAC地址是数据链路层和物理层使用的地址,是写在网卡上的物理地址,用来定义网络设备的位置,不可变更。
- IP地址是网络层和以上各层使用的地址,是一种逻辑地址。IP地址用来区别网络上的计算机。
为什么有了MAC地址还需要IP地址?
- 如果我们只使用MAC地址进行寻址的话,我们需要路由器记住每个MAC地址属于哪个子网,不然一次路由器收到数据包都要满世界寻找目的MAC地址。而我们知道MAC地址的长度为48位,也就是最多共有2的48次方个MAC地址,这就意味着每个路由器需要256T的内存,显然是不现实的。
- 和MAC地址不同,IP地址是和地域相关的,在一个子网中的设备,我们给其分配的IP地址前缀都是一样的,这样路由器就能根据IP地址的前缀知道这个设备属于哪个子网,剩下的寻址就交给子网内部实现,从而大大减少了路由器所需要的内存。
为什么有了IP地址还需要MAC地址?
- 只有当设备连入网络时,才能根据他进入了哪个子网来为其分配IP地址,在设备还没有IP地址的时候,或者在分配IP的过程中。我们需要MAC地址来区分不同的设备。
- IP 地址可以比作为地址,MAC 地址为收件人,在一次通信过程中,两者是缺一不可的。
(10)说下 ping 的原理?
- ping,Packet Internet Groper,是一种因特网包探索器,用于测试网络连接量的程序。Ping 是工作在 TCP/IP 网络体系结构中应用层的一个服务命令, 主要是向特定的目的主机发送 ICMP(Internet Control Message Protocol 因特网报文控制协议) 请求报文,测试目的站是否可达及了解其有关状态。
-
一般来说,ping 可以用来检测网络通不通。它是基于ICMP协议工作的。假设机器 A ping 机器 B,工作过程如下:
- ping 通知系统,新建一个固定格式的 ICMP 请求数据包。
- ICMP 协议,将该数据包和目标机器 B 的 IP 地址打包,一起转交给 IP 协议层。
- IP 层协议将本机 IP 地址为源地址,机器 B 的 IP 地址为目标地址,加上一些其他的控制信息,构建一个 IP 数据包。
- 先获取目标机器 B 的 MAC 地址。
- 数据链路层构建一个数据帧,目的地址是 IP 层传过来的 MAC 地址,源地址是本机的 MAC 地址。
- 机器 B 收到后,对比目标地址,和自己本机的 MAC 地址是否一致,符合就处理返回,不符合就丢弃。
- 根据目的主机返回的 ICMP 回送回答报文中的时间戳,从而计算出往返时间。
- 最终显示结果有这几项:发送到目的主机的 IP 地址、发送 & 收到 & 丢失的分组数、往返时间的最小、最大 & 平均值。
9. WebSocket
(1)握手过程:
- 浏览器、服务器建立 TCP 连接,三次握手。
- TCP 连接成功后,浏览器通过 HTTP 协议向服务器传送 WebSocket 支持的版本号等信息。
- 服务器收到客户端的握手请求后,同样采用 HTTP 协议回馈数据。
- 当收到了连接成功的消息后,通过 TCP 通道进行传输通信。
(2)WebSocket 与 HTTP 的关系:
- 相同点:
- 都是基于 TCP 的、可靠的传输协议。
- 都是应用层协议。
- 不同点:
- WebSocket 是双向通信协议,模拟 Socket 协议,可以双向发送或接受信息。HTTP 是单向的。
- WebSocket 是需要握手进行建立连接的。
- 联系:
- WebSocket 在建立握手时,数据是通过 HTTP 传输的。但是建立之后,在真正传输的时候是不需要HTTP 协议的。
(3)WebSocket 与 Socket 关系:
- Socket 其实并不是⼀个协议,而是为了方便使用 TCP 或 UDP 而抽象出来的⼀层,是位于应用层和传输层之间的⼀组接口。当两台主机通信时,必须通过 Socket 连接,Socket 则利用 TCP/IP协议建立 TCP 连接。TCP 连接则更依靠于底层的 IP 协议,IP 协议的连接则依赖于链路层等更低层次。
- WebSocket 是一个持久化的协议,它是伴随 H5 而出的协议,用来解决 http 不支持持久化连接的问题。
- Socket 一个是网编编程的标准接口。而WebSocket 则是⼀个典型的应用层协议。
(4)WebSocket 与 HTML5 的关系:
- WebSocket API 是 HTML5 标准的⼀部分,但这并不代表 WebSocket ⼀定要用在 HTML 中,或者只能在基于浏览器的应用程序中使用。实际上,许多语言、框架和服务器都提供了 WebSocket 支持。
10. DHCP
(1)DHCP( 动态主机配置协议 )是⼀个局域网的网络协议。指的是由服务器控制⼀段IP地址范围,客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码。DHCP 客户端进程监听的是 68 端口号,DHCP 服务端进程监听的是 67 端口号。4 个步骤:(详细的介绍见博客《IP协议》的第四小节)
- 客户端首先发起 DHCP 发现报文(DHCP DISCOVER) 的 IP 数据报,由于客户端没有 IP 地址,也不知道 DHCP 服务器的地址,所以使用的是 UDP ⼴播通信,其使用的广播目的地址是255.255.255.255(端口 67) 并且使用 0.0.0.0(端口 68) 作为源 IP 地址。DHCP 客户端将该IP 数据报传递给链路层,链路层然后将帧⼴播到所有的网络中设备。
- DHCP 服务器收到 DHCP 发现报文时,用 DHCP 提供报文(DHCP OFFER) 向客户端做出响应。该报文仍然使用 IP 广播地址 255.255.255.255,该报文信息携带服务器提供可租约的 IP 地址、子网掩码、默认网关、DNS 服务器以及 IP 地址租用期。
- 客户端收到⼀个或多个服务器的 DHCP 提供报文后,从中选择⼀个服务器,并向选中的服务器发送 DHCP 请求报文进行响应,回显配置的参数。
- 最后,服务端用 DHCP ACK 报文对 DHCP 请求报文进行响应,应答所要求的参数。
- ⼀旦客户端收到 DHCP ACK 后,交互便完成了,并且客户端能够在租用期内使用 DHCP 服务器分配的 IP 地址。
(2)如果租约的 DHCP IP 地址快到期后,客户端会向服务器发送 DHCP 请求报文:
- 服务器如果同意继续租用,则用 DHCP ACK 报文进行应答,客户端就会延长租期。
- 服务器如果不同意继续租用,则用 DHCP NACK 报文,客户端就要停止使用租约的 IP 地址。
- 可以发现,DHCP 交互中,全程都是使用 UDP 广播通信。
(3)如果 DHCP 服务器和客户端不是在同⼀个局域网内,路由器又不会转发广播包,为了解决这⼀问题,就出现了 DHCP 中继代理。有了 DHCP 中继代理以后,对不同网段的 IP 地址分配也可以由⼀个 DHCP服务器统⼀进行管理。
- DHCP 客户端会向 DHCP 中继代理发送 DHCP 请求包,而 DHCP 中继代理在收到这个广播包以后,再以单播的形式发给 DHCP 服务器。
- 服务器端收到该包以后再向 DHCP 中继代理返回应答,并由 DHCP 中继代理将此包⼴播给 DHCP客户端 。
- 因此,DHCP 服务器即使不在同⼀个链路上也可以实现统⼀分配和管理IP地址
11. NET
(1)由于绝大多数的网络应用都是使用传输层协议 TCP 或 UDP 来传输数据的。因此,可以把 IP 地址 + 端口号⼀起进行转换。这样,就用⼀个全球 IP 地址就可以了,这种转换技术就叫网络地址与端口转换NAPT。
- 这种转换表在 NAT 路由器上自动生成。例如,在 TCP 的情况下,建立 TCP 连接首次握手时的 SYN 包⼀经发出,就会生成这个表。而后又随着收到关闭连接时发出 FIN 包的确认应答从表中被删除。
(2)由于 NAT/NAPT 都依赖于自己的转换表,因此会有以下的问题:
- 外部无法主动与 NAT 内部服务器建立连接,因为 NAPT 转换表没有转换记录。
- 转换表的生成与转换操作都会产生性能开销。
- 通信过程中,如果 NAT 路由器重启了,所有的 TCP 连接都将被重置
(3)解决的方法:
- 第⼀种改用 IPv6:IPv6 可用范围非常大,以至于每台设备都可以配置⼀个公有 IP 地址,就不搞那么多花⾥胡哨的地址转换了,但是 IPv6 普及速度还需要一些时间。
- 第⼆种 NAT 穿透技术:客户端主动从 NAT 设备获取公有 IP 地址,然后自己建立端口映射条目,并用这个条目对外通信,就不需要 NAT 设备来进行转换了。
12. IGMP
(1)IGMP 是因特网组管理协议,工作在主机(组播成员)和最后⼀跳路由之间。
- IGMP 报文向路由器申请加入和退出组播组,默认情况下路由器是不会转发组播包到连接中的主机,除非主机通过 IGMP 加入到组播组,主机申请加荣耀到组播组时,路由器就会记录 IGMP 路由器表,路由器后续就会转发组播包到对
应的主机了。IGMP 报文采用 IP 封装,IP 头部的协议号为 2,而且 TTL 字段值通常为 1,因为 IGMP是工作在主机与连接的路由器之间。
(2)常规查询与响应工作机制:
- 路由器会周期性发送目的地址为 224.0.0.1(表示同⼀网段内所有主机和路由器) IGMP 常规查询报文。
- 主机收到这个查询,随后会启动「报告延迟计时器」,计时器的时间是随机的,通常是 0~10 秒,计时器超时后主机就会发送 IGMP 成员关系报告报文(源 IP 地址为自己主机的 IP 地址,目的 IP地址为组播地址)。如果在定时器超时之前,收到同⼀个组内的其他主机发送的成员关系报告报文,则自己不再发送,这样可以减少网络中多余的 IGMP 报文数量。
- 路由器收到主机的成员关系报文后,就会在 IGMP 路由表中加入该组播组,后续网络中⼀旦该组播地址的数据到达路由器,它会把数据包转发出去。
(3)离开组播组工作机制:
- 主机 1 要离开组 224.1.1.1,发送 IGMPv2 离组报文,报文的目的地址是 224.0.0.2(表示发向网段内的所有路由器)。
- 路由器 收到该报文后,以 1 秒为间隔连续发送 IGMP 特定组查询报文(共计发送 2 个),以便确认该网络是否还有 224.1.1.1 组的其他成员。
- 主机 3 仍然是组 224.1.1.1 的成员,因此它立即响应这个特定组查询。路由器知道该网络中仍然存在该组播组的成员,于是继续向该网络转发 224.1.1.1 的组播数据包。否则不会再向这个网段转发该组播地址的数据包。