计算机网络面试问题笔记
网络模型
TCP/IP 模型?
从上到下分为四层:
- 应用层:直接为用户提供的各种服务,定义了应用进程间的通信规则,如 HTTP、FTP 等
- 传输层:为应用层实体提供端到端、通用的通信功能,保证了数据包的顺序传送及数据的完整性。协议包括 TCP、UDP 等。
- 网络层:解决主机到主机之间的路由问题,包括 IP、ICMP 等。
- 链路层:负责相邻物理节点的可靠数据传输,协议包括 ARP 等。
OSI 七层模型和 TCP/IP 四层模型差别?
- OSI 将 TCP/IP 的应用层分为了会话层、表示层和应用层
- OSI 将物理层单独列为一层
- OSI 的网络层既提供面向连接的服务,又提供无连接的服务;TCP/IP 的网络层纸提供无连接的网络服务
- OSI 的传输层只提供面向连接的服务;TCP/IP 的传输层既提供面向连接的 tcp 又提供无连接的 udp。
重要协议和概念
一些重要协议?
- DNS:应用层协议,用于映射域名和 IP 地址
- DHCP:应用层协议,动态分配 IP 地址。
- IP:网络层协议,用于分组交换数据网络,功能包括寻址、路由、尽最大努力交付包等。
- ICMP:网络层协议,互联网控制消息协议,用于返回通信环境的错误信息。traceroute 和 ping 都基于 ICMP。例如 traceroute 是通过特殊 TTL 的包接收 ICMP 超时消息和不可达消息实现的。
- RIP:路由信息协议,网络层协议,是一种内部网关协议(IGP),通过距离向量实现。
- OSPF:开放式最短路优先,网络层协议,是一种内部网关协议(IGP),通过 dijkstra 实现。
- BGP:边界网关协议,网络层协议,是一种域间路由协议,用于网络间网关的路由
- ARP:地址解析协议,链路层协议,通过 IP 寻找 MAC 地址。因为用到 IP,所以也有说是网络层协议。
一些重要概念?
- 集线器:物理层硬件,连接所有线路、广播所有信息。
- 网桥、交换机:链路层硬件,隔离端口、根据 MAC 转发。
- 路由器:网络层的硬件,根据 IP 寻址。
- 不同协议的数据单元:
- 物理层:Bit
- 链路层:帧 Frame
- 网络层:分组、数据包 Packet
- 传输层:数据段
- MSL:报文最大生存时间,是TCP报文在网络上存在的最大时间,超过报文会被丢弃。
- TTL:IP 数据报在网络中可以存活的总跳数,如果跳太多就会被丢弃,同时产生一个 ICMP 报文通知源主机。
- RTT:客户端到服务端往返的时间,由 TCP 动态地估算。
TCP
TCP 头格式?
TCO头格式如下:
可以看出几个要点:
- TCP 的包没有 IP 地址,因为那是 IP 层的事,只包含源端口和目的端口。
- Sequence Number 是包的序号,解决乱序问题
- Acknowledge Number 就是 ACK,用于确认收到,解决丢包的问题
- Window:滑动窗口,解决流量控制问题
- TCP flag:标记包的类型,用于操控 tcp 状态机。
TCP 的流量控制?
流量控制的目的是控制发送端的发送速度,使其按照接收端的数据处理速度来发送数据,避免接收端处理不过来,产生拥塞或丢包。
流量控制的实现方式是引入滑动窗口,发送端和接收端各维护一个,对应一个缓冲区,记录当前发送或收到的数据。接收端会在返回的 ACK 报文里包含自己可用于接收数据的缓冲区的大小,在首部的 window (16位,最高65535字节)里表示。发送端发送的数据不会超过 window 的大小。具体来说,发送方会维护三个指针,分别表示已发未确认的位置、当前发送到的位置、当前允许发送的最前位置,第一个和第三个指针之间的就是滑动窗口,第二个指针只能在窗口内移动(发新的报文),第一和第三个指针同步移动。
TCP 的拥塞控制?
当等待接收端的 ACK 超时或者收到乱序包时,说明网络出现了拥塞。发送端会维护一个拥塞窗口 cwnd,拥塞窗口大小取决于网络的拥塞程度动态变化。
连接建立时,初始化 cwnd =1,进入慢启动状态,每收到一个 ACK 窗口++,每经过一个 RTT 窗口翻倍(指数增长)。当窗口增长超过一个阈值,会进入拥塞避免阶段。
在拥塞避免阶段,每收到一个 ACK 包, cwnd += 1/cwnd,会以曲线形式不断试探网络的上限。如果发送端超时未收到 ACK,就认为网络出现了堵塞,进入超时重传阶段。
超时出现后,立即把窗口增长阈值设为当前拥塞窗口的一半,窗口大小重置为1,又开始慢启动过程。
除此之外,tcp 还有一个快速重传和快速恢复的机制。接收端在收到乱序包的时候就会发送 duplicate ACK 通知发送端, 发送端接收到三个重复的 ACK 时就会立刻开始重传,而不用等到计时器超时,同时会配合快速恢复,将阈值设为当前拥塞窗口的一半,并将窗口大小重置为阈值,开始拥塞避免过程。
TCP 标志位?
TCP 标志位标志了请求的目的:
- SYN:同步标志,用来建立连接。请求连接和确认连接请求时,SYN=1.
- ACK:确认标志,表示确认收到请求。
- FIN:结束标志,表示关闭一个 tcp 连接
- PSH:表示推送操作,就是指数据包到达接收端后不对齐进行队列处理,而是尽可能给的将数据交给应用程序处理
- RST:重置复位标志,用于复位对应的 TCP 连接
- URG:紧急标志,用于保证 TCP 不被中断,督促中间设备尽快处理。
为什么是三次握手?
- 如果是两次握手,服务端发送确认报文后,客户端有可能没有收到,但服务端已进入连接状态,导致服务器资源浪费。
- 如果是四次握手,因为使用三次握手是建立连接的最少次数,所以没必要加入第四次。
- 第一次握手服务端确认了客户端的发送和自己的接收功能;第二次握手客户端确认了服务端的接收、发送和自己的接收、发送功能,客户端认为连接已建立;第三次握手服务端确认了客户端的接收功能和自己的发送功能,服务端认为连接已建立。
SYN 攻击和如何防范?
SYN 攻击是 DDOS 的一种,利用了 tcp 协议的缺陷,发送大量随机伪造的 IP 的第一次握手请求,使得服务器进入半连接状态并向虚假的 IP 地址发送第二次握手。由于地址是虚拟的,服务器会维持半连接状态并重试发送直到超时。这些伪造的 SYN 包大量占用未连接队列,影响正常请求。
对于防范方法,只能通过引入网关、防火墙,或者增加允许的半连接数上限、降低半连接超时时间等方法减小危害,除非修改协议,否则不能完全杜绝。
为什么需要四次挥手?
因为 tcp 是全双工的,一方关闭连接后另一方仍然可以发送数据。所以四次挥手是把断开连接分成两个独立的部分。
为什么第四次挥手后客户端的 time-wait 状态要持续到 2MSL 以后?
- 确保 ACK 能到达服务端,使服务端能正确关闭
MSL 是报文段在网络上存活的最大时间。2 MSL 即客户端报文超时+服务端报文重传,这样才能够收到服务器重传的 FIN 报文、重置 2MSL 计时器、重传 ACK 报文,以确保服务端能够收到 ACK 报文并正确关闭连接。
- 防止已失效的连接请求报文段出现在之后的连接中
在客户端发送最后一个 ACK 后,网络里仍然可能残留有之前的报文段,此时客户端仍然可以针对这些报文段发送 ACK。持续 2MSL 的 time-wait结束后,可以使得本连接产生的报文在网络内处理完毕,避免与后续连接产生混淆。即使后续收到了过时的报文也可以选择不处理。
注:time_wait 是主动断开连接的一方会进入的状态。
如果建连后客户端挂了怎么办?
TCP 设有一个保活计时器,若2小时都没有收到客户端的任何消息,服务器就开始重试,每隔 75 秒就发一个探测报文段,若连发10次都没有回应,就认为连接已经断开了。
TCP 握手和挥手至少需要几个RTT?
建连时,在第三次握手的时候就可以传递数据了,因此我们计时只计算前两次挥手,即一个来回,也就是一个RTT。
断连时总共四次挥手,所以至少需要两个RTT。
HTTP / HTTPS
HTTP 协议个版本特性?
- HTTP/1.0:默认使用短连接,请求一个静态资源就建立一个连接
- HTTP/1.1:默认支持长连接,打开一个网页期间所有请求都走一个连接;引入了额外的缓存控制机制;增加了更多错误码;引入了内容协商和响应分块(断点续传);引入了管线化,允许客户端并行发送多个请求(但是服务端必须按顺序串行返回)。
- HTTP/2.0:采用二进制格式传输,不再采用文本格式;对于 header 中相同的数据不会重复发送,从而做到 header 压缩;服务器可以对一个客户端请求返回多个响应,推送资源无需明确的请求;二进制分帧将信息分为若干个帧,引入流的概念支持了多路复用,同一个 tcp 连接可以同时交错发送多个消息的帧,从而实现双向的并行传输。
- HTTP/3.0 / QUIC:虽然 http/2 解决了很多问题,但在移动互联网时代,连接地址经常更换,tcp 的四元组(源和目的IP、端口)变化时就需要重新建连,导致大量开销;虽然 http 协议的复用阻塞解决了,但是 tcp 的队头阻塞没有解决,所有的流都在一条 tcp 上,如果某个流的某个包丢包,这个包后面所有的其他流的数据都不能被读取。除此之外,还有一些流优先级的问题。这些问题不能通过修改 http 解决,只能替换 tcp,因此引入了 QUIC 来替换 tcp。QUIC 底层采用 udp,不再维护基于IP-端口四元组的连接,而是使用缓存的 connection ID,这样网络切换后也可以不建连恢复到之前的连接。同时 QUIC 依然和 tcp 一样通过 ACK 机制实现可靠传输、流量控制、拥塞控制等功能。QUIC 取代了之前 tcp+TSL 的叠加模式所需要的 3个 RTT,第一次建连之后使用缓存的秘钥通信,这样之后客户端第一次握手就可以传递应用数据,实现所谓 0-RTT 握手。
数字签名和数字证书是什么?
使用公私钥的系统中,客户端需要向服务端申请公钥,服务端保留私钥,然后使用这个公钥来和服务端通信,这样只要私钥不泄露,客户端->服务端的通信就是保密的。但是由于中间网络是不可控的,数据有可能会被篡改,所以需要引入数字签名
,也就是一个被公钥加密过的 数据的hash值,来验证消息是否被修改过。客户端用公钥解密、验证哈希值匹配,就说明没有被篡改。
但是还有个问题,如果一开始客户端申请公钥时就被篡改,那客户端有可能就会拿着假的公钥一直和假的服务端发信了。因此,需要引入一种方法来确保公钥的真实性。这时候就需要引入证书中心 CA
,服务端找证书中心为公钥做认证,证书中心用自己的私钥对服务端的公钥和一些相关信息(网址)一起加密,生成数字证书
。之后服务端发信时同时附带数字签名和数字证书,客户端拿到以后用 CA 的公钥解开证书,比对要访问的网址和证书的记录和过期时间,就可以确认是否是正确的公钥了。
那么如何保证客户端获得的 CA 的公钥就不被篡改呢?这时候就需要引入根证书
,这种证书是在浏览器或者操作系统本地固定储存的,不会经过网络,且只保存一些受信的CA。同时根证书也会定期刷新,避免私钥被暴力破解。
SSL/TLS 握手的详细过程?
- 客户端向服务端发起加密通信请求 clientHello,向服务端提供支持的协议版本、一个客户端生成的随机数、之后用到的对称加密和压缩的方法等。
- 服务端回应 serverHello,包含确认使用的通信版本、一个服务器生成的随机数、确认的对称加密方法以及服务器证书。如果采用双端验证,即服务端也需要验证客户端身份,会再加入一个请求要求客户端提供客户端证书。
- 客户端收到证书后会进行验证,判定其是否是可信机构发布、证书的域名与实际域名是否一致、证书是否已过期,然后从证书中取出公钥,用公钥加密向服务器继续发信,包括一个随机数、编码改变通知、客户端握手结束通知(同时也是前面内容的哈希值)。自此,两边都有了三个不同主机生成的随机数(之所以用三个,是为确保至少有一方生成的随机数是随机的,这样会话密钥才是随机的)。
- 服务端收到第三个随机数后,就可以生成本次会话所用的
会话密钥
,然后向客户端发送编码改变通知和服务器握手结束通知(也是前面内容的哈希值)。至此握手阶段结束,之后的通信就采用协商好的对称加密算法,以三个随机值导出的会话密钥为 key 进行加密通信。
其他
从输入一个 URL 到页面加载完成的过程?
一个经典的计网面试题,既有广度又有深度,字节三面被问过。
-
整体流程:
用户按下回车,浏览器会新开一个网络线程,发起HTTP请求;
浏览器会进行 DNS 查询,将域名解析为 IP 地址;
浏览器获得 IP 地址后向服务器请求建立 TCP 连接;
浏览器向服务器发起 HTTP请求;
服务器处理请求,返回 HTTP 响应;
浏览器渲染进程解析并绘制页面。
-
应用层进行DNS查询,浏览器搜索自身和操作系统的DNS缓存,读取本地Host文件和向本地DNS服务器进行查询等。如果没有,则逐级向上层DNS服务器查询,直到根DNS服务器。
-
应用层生成 HTTP 请求报文,包括首部和主体部分。
-
传输层建立TCP连接,客户端打开一个 socket 与目标IP、端口建立 TCP 连接,进行三次握手;如果是 https,则再进行四次 SSL 握手。
-
网络层使用 IP 协议栈选择路线,将来自传输层的数据段装入数据包,填充包头(IP地址、源地址),主要就是添加源和目的 IP 地址,然后发送数据。在数据传输的过程中,IP 协议负责选择传送的路线,称为路由。
-
数据链路层实现网络相邻节点间的可靠传输,将数据包封装成帧,按顺序传送各帧,为其分别做冗余校验和出错重传。
-
物理层将帧转换为二进制的比特流,以物理信号在介质中传输。
-
服务器网卡收到数据,放入操作系统的接收队列,协议栈层层解包,借助 epoll 通知应用层服务器处理。服务器经过各种负载均衡或反向代理后转发到实际的服务器端口,生成响应报文,再一层层封装发送。
-
最终客户端的浏览器收到报文并解析 html、绘制页面。
socket 通信流程?
参考 Linux 网络收包与 IO 多路复用 - tk_sky的博客 (mcyou.cc)