前言
这篇文章只要是我通过ai以及自己总结考点,列举了一些关于网络相关的面试题,可能会在我们实习面试以及秋招中遇到,适合学习完网络部分知识来进行一下检验,里面包含了我的回答以及ai的回答,来看看你有没有我这类似的问题,并且我会将我的答案交给ai来打分【本文还没有涉及http相关内容,后续会进行更新】
1,TCP/IP五层模型分别负责什么?
我答:
应用层负责组织好我们要发送的数据,就好比一条微信消息可能需要将发送方的用户名,数据的时间,数据具体内容以及接收方的用户名一起包装起来,这个是和微信内部的数据组织形式有关系;传输层是数据和网络建立连接,并且决定数据传输的类型是TCP还是UDP;网络层是获取ip信息,得知数据传输的来源以及目的地;数据链路层拿到mac地址,两个网络段之间的传输方式;物理层是将数据通过网络,或者网线传输出去
ai打分,改错以及回答:
评分:60/100。
你已经能说出五层的名称,也抓住了应用数据、TCP/UDP、IP、MAC和传输介质这些关键词。不过按实习面试标准,目前存在比较明显的层级职责混淆,面试官继续追问时容易答乱。
你的不足主要有以下几点:
-
应用层的例子不错,但还缺少"通信规则"
微信消息确实需要组织发送者、接收者、时间和内容,但应用层除了规定数据格式,还规定双方如何理解和处理这些数据。核心是通信双方遵守同一套应用协议。
-
传输层不是"数据和网络建立连接"
只有TCP需要建立连接,UDP不建立连接。传输层的核心任务是实现进程到进程的通信,通过端口号定位具体程序,并提供TCP或UDP等不同传输服务。
-
不是网络层负责"获取IP信息"
获取IP地址可能涉及手动配置或DHCP。网络层的主要职责是使用IP地址进行逻辑寻址,并通过路由选择,让数据跨越多个网络到达目标主机。
-
数据链路层不负责"两个网络段之间的传输"
不同网络之间的转发主要是网络层和路由器的职责。数据链路层负责当前链路或当前这一跳的传输,例如把IP数据包封装成以太网帧,通过MAC地址和交换机完成局域网内的交付。
-
物理层的描述还不够准确
物理层传输的是比特流。它会把数据转换为电信号、光信号或无线电信号,通过网线、光纤或无线介质发送。
面试中可以这样回答:
TCP/IP五层模型从上到下分别是应用层、传输层、网络层、数据链路层和物理层。
应用层负责定义应用程序之间如何组织和交换数据。比如微信发送一条消息,需要规定消息中包含发送者、接收者、发送时间和具体内容,同时发送方和接收方必须遵守相同的数据格式和交互规则,接收方才能正确解析。
传输层负责进程到进程之间的通信。它通过端口号确定数据应该交给主机中的哪个应用程序,并提供TCP和UDP两种常见传输服务。TCP是面向连接的可靠字节流协议,UDP是无连接的数据报协议。一般是应用程序根据业务需要选择使用TCP还是UDP,并不是传输层临时替应用程序决定。
网络层负责主机之间的跨网络通信。它使用源IP和目的IP进行逻辑寻址,并通过路由表确定下一跳,使数据能够经过多个路由器到达目标主机。网络层的重点是IP地址和路由,而不只是获取IP地址。
数据链路层负责当前链路上的数据传输。它会把网络层的IP数据包封装成帧,通过源MAC地址和目的MAC地址完成当前这一跳的交付。在以太网局域网中,交换机通常根据MAC地址表转发以太网帧。
物理层负责传输最底层的比特流。它把数据表示为电信号、光信号或者无线信号,再通过网线、光纤或无线介质传输出去。
数据发送时会从应用层向下逐层封装,接收方收到后再从物理层向上逐层解封装。可以概括为:应用层规定数据的含义,传输层负责进程通信,网络层负责跨网络路由,数据链路层负责当前一跳,物理层负责传输比特。
2. IP、MAC和ARP之间是什么关系?
我答:
ip主要负责找到最终目的地,mac是找到当前的网络段的下一跳的目标,arp是在路由器当中的一个广播,协助mac找到下一跳,比如是要找ip为120.X.X.X的目的ip,进行arp广播看看有没有认识这个ip的,如果有一个ip是120.168.0.1的,那么就交给它
ai打分,改错以及回答:
评分:45/100。
你已经抓住了两个重要方向:
- IP指向最终通信目标。
- MAC负责当前一跳的交付。
但你对ARP工作过程的理解存在关键错误。这道题面试官通常会继续追问同网段、跨网段以及默认网关,因此需要马上纠正。
主要不足如下:
-
ARP不只存在于路由器中
普通电脑、服务器和路由器都可以使用ARP。只要设备需要在IPv4局域网中根据IP地址获取MAC地址,就可能发起ARP请求。
-
ARP广播不能跨越路由器
ARP广播只在当前局域网或广播域内传播。你的电脑不能通过ARP询问互联网中的设备。
-
不会广播询问"谁认识120.X.X.X"
如果
120.X.X.X不在本地子网,电脑不会查询它的MAC地址,而是查询默认网关的MAC地址。 -
路由器不是通过ARP判断谁认识远端IP
路由器先查询自己的路由表,通过最长前缀匹配确定出口和下一跳,然后才可能使用ARP查询下一跳设备的MAC地址。
-
需要区分IP数据包和以太网帧
访问远端服务器时,IP数据包的目的IP仍然是远端服务器,当前以太网帧的目的MAC则是默认网关。
面试中可以这样回答:
IP地址、MAC地址和ARP分别解决不同的问题。
IP地址是网络层的逻辑地址,负责标识最终的源主机和目的主机。路由器会根据IP数据包中的目的IP查询路由表,决定数据下一步应该往哪里转发。
MAC地址是数据链路层地址,主要负责当前链路上的实际交付。也就是说,IP地址关注最终目的地,MAC地址关注当前这一跳应该把数据交给哪台设备。
ARP的作用是在IPv4局域网中,根据一个已知IP地址查询对应的MAC地址。ARP请求通常以广播形式发送,拥有这个IP地址的设备收到后,会把自己的MAC地址回复给请求方。
发送数据前,主机会先使用IP地址和子网掩码判断目标是否与自己处于同一个子网。
如果目标在同一个子网,主机会直接通过ARP查询目标主机的MAC地址,然后把以太网帧发送给目标主机。
如果目标不在同一个子网,主机不会查询远端服务器的MAC地址,而是查询默认网关的MAC地址。随后,IP数据包的目的IP仍然是远端服务器,但当前以太网帧的目的MAC是默认网关的MAC。
路由器收到数据后,会拆掉原来的以太网帧,检查IP数据包的目的IP,查询路由表确定下一跳,再使用新的源MAC和目的MAC封装成新的帧继续发送。因此,数据经过路由器时MAC地址通常逐跳变化,而IP地址通常保持不变,经过NAT时IP可能被修改。
可以用一个具体例子说明。
假设:
本机IP:192.168.1.10
子网掩码:255.255.255.0
默认网关:192.168.1.1
目标服务器:120.10.20.30
过程是:
-
本机计算后发现
120.10.20.30不在192.168.1.0/24子网中。 -
本机决定把数据交给默认网关
192.168.1.1。 -
本机广播询问:"谁拥有
192.168.1.1?请告诉我你的MAC地址。" -
默认网关返回自己的MAC地址。
-
本机发送的数据大致是:
IP数据包:
源IP = 192.168.1.10
目的IP = 120.10.20.30当前以太网帧:
源MAC = 本机MAC
目的MAC = 默认网关MAC -
默认网关收到后,根据目的IP
120.10.20.30查询路由表,并向下一跳转发。
这道题最应该记住的一句话是:
IP负责端到端寻址,MAC负责一跳一跳交付,ARP负责在当前IPv4链路中把下一跳IP解析成MAC。
另外,你原回答中的"如果有一个IP是120.168.0.1,那么就交给它"需要删掉。正确逻辑是:
先用路由表确定下一跳IP,再通过ARP获取这个下一跳的MAC。
并且发送端主机以及沿途路由器都会查询路由表
3. DNS解析过程是什么?
我答:
先检查浏览器有无地址的相关缓存,再查看host文件,再给DNS的服务器发起查询请求,最后将结果返回个客户端
ai打分,改错以及回答:
评分:48/100。
你的回答方向正确,已经提到了浏览器缓存、hosts文件、DNS服务器和结果返回。但完整的DNS解析主要发生在递归DNS服务器中,这一段目前完全缺失。
主要不足如下:
-
遗漏了操作系统DNS缓存
浏览器没有结果后,通常还会经过操作系统的名称解析机制,包括系统DNS缓存和hosts文件。
-
"DNS服务器"说得太笼统
客户端通常先请求配置好的递归DNS服务器,例如运营商DNS、学校DNS或者公共DNS。
-
没有解释递归DNS服务器如何找到答案
缓存未命中时,需要继续查询根DNS、顶级域DNS和权威DNS。
-
没有区分递归查询和迭代查询
客户端希望递归DNS直接返回结果;递归DNS查找答案时,会根据其他DNS服务器给出的转介信息继续查询。
-
没有提到DNS缓存的TTL
查询结果通常按照TTL缓存,并不是每次访问都完整查询一遍。
-
表达不够口语化、完整
"查看host文件,再给DNS服务器发起请求"只能算流程开头,面试官大概率会追问DNS服务器内部发生了什么。
面试中可以这样回答:
DNS的作用是把域名解析成对应的IP地址。我一般把DNS解析分成本地查询和DNS服务器查询两个阶段。
用户输入域名后,浏览器会先尝试从自己的缓存中查找解析结果。没有找到时,会交给操作系统的名称解析机制处理。操作系统可能检查自己的DNS缓存和hosts文件。具体检查顺序会受到操作系统配置影响,所以不需要把顺序说得绝对固定。
如果本地仍然没有结果,客户端会向网络配置中指定的递归DNS服务器发送查询请求,例如运营商DNS、学校DNS或者公共DNS。
递归DNS服务器首先检查自己的缓存。如果缓存中存在并且没有过期,就直接把结果返回给客户端。
如果缓存中也没有结果,递归DNS服务器会继续寻找答案。以查询
www.example.com为例,它可能先询问根DNS服务器。根服务器一般不会直接返回最终IP,而是告诉它应该去查询负责.com的顶级域DNS服务器。递归DNS再询问
.com顶级域DNS服务器,顶级域服务器会告诉它example.com对应的权威DNS服务器。递归DNS最后向权威DNS服务器查询,获得www.example.com对应的A记录、AAAA记录,或者先获得CNAME记录后继续查询。得到最终结果后,递归DNS会按照记录的TTL缓存结果,并把IP地址返回给客户端。客户端也可能缓存这个结果,之后浏览器才能使用该IP建立后续网络连接。
可以把流程记成:
浏览器和本机查询
→ 递归DNS缓存
→ 根DNS
→ 顶级域DNS
→ 权威DNS
→ 返回IP并按照TTL缓存
递归查询和迭代查询
面试官很可能接着问这一点。
客户端向递归DNS服务器发起的通常是递归查询,意思是客户端希望DNS服务器直接返回最终答案或错误。递归DNS服务器寻找答案时,其他DNS服务器可能只告诉它下一步应该询问谁,这属于迭代式查找过程。
进一步追问:DNS使用TCP还是UDP?
可以回答:
传统DNS查询通常优先使用UDP,因为开销较小。如果响应被截断、需要更可靠地传输较大数据,客户端可能改用TCP。现在还存在通过HTTPS传输DNS的DoH,以及通过TLS传输DNS的DoT。
理解+:递归查询一般发生在询问递归DNS服务器的时候,迭代查询是在递归DNS查不到的时候,然后递归DNS会一级一级往上询问,这个时候是迭代查询,不过他们并不会直接给你返回一个ip,而是我知道你下一步往哪走,然后你继续往那里查询;TTL缓存就相当于你刚查了一个网站,那它的ip会先记录下来,一般假设存活300秒,然后这个时间内,你重新访问这个网页,就不需要刚刚拿全部的繁琐操作,直接在这个缓存里就可以找到,也减少了dns服务器的压力,时间到了这个缓存就没用了,就需要重新向上查找
4. TCP和UDP有什么区别?
我答:
TCP保障可靠传输,需要建立连接,面向字节流,因为需要考虑可靠的缘故,有确认应答,超时重传,滑动窗口等机制,传输效率较慢,UDP不可靠传输,面向数据报,效率较高
ai打分,改错以及回答:
评分:78/100。
这个回答已经达到基础合格水平。TCP可靠、需要建立连接、面向字节流,以及UDP面向数据报、开销较小,这些核心区别都答对了。
主要不足如下:
-
"TCP效率慢、UDP效率高"过于绝对
更准确的说法是TCP通常具有更大的协议开销和连接建立延迟,UDP协议更轻量。但实际传输效率和吞吐量还取决于网络环境、程序设计和业务场景。
-
"UDP不可靠"需要解释清楚
UDP不是一定会丢包,而是UDP协议本身不提供送达确认、重传、排序和去重保证。应用层可以在UDP上自行实现可靠机制,例如QUIC。
-
遗漏了有序传输
TCP会根据序列号对数据重新排序,向应用程序提供有序字节流;UDP不保证数据报按发送顺序到达。
-
遗漏了消息边界
TCP面向字节流,不保留每次发送的消息边界,因此应用层需要处理粘包和拆包。UDP面向数据报,通常会保留数据报边界。
-
遗漏了流量控制与拥塞控制的作用
滑动窗口只是一个总称,还应该说明TCP使用接收窗口进行流量控制,并使用拥塞窗口保护网络。
-
缺少使用场景
面试中补充典型场景,可以证明你不是只背定义。
面试时可以这样回答:
TCP和UDP都是传输层协议,都可以通过端口号实现进程之间的通信,但它们提供的传输服务不同。
TCP是面向连接的协议。通信双方正式传输数据前,需要先建立连接。TCP向应用程序提供可靠、有序的字节流服务,它会通过序列号、确认应答、校验和、超时重传等机制处理数据丢失、重复和乱序问题。
TCP还使用滑动窗口提高传输效率,通过接收窗口进行流量控制,避免发送速度超过接收方的处理能力;同时使用拥塞窗口进行拥塞控制,避免向网络中发送过多数据。
TCP面向字节流,不保留应用程序每次发送数据时的消息边界。例如发送方连续发送两条消息,接收方可能一次全部读取,也可能分成多次读取,因此应用层需要通过长度字段、分隔符等方式处理消息边界。
UDP是无连接的数据报协议,发送数据前不需要建立连接。UDP会保留数据报边界,但协议本身不保证数据一定送达,也不保证数据的到达顺序,同时没有TCP提供的重传、流量控制和拥塞控制机制。
因为UDP不需要握手,协议头和状态管理也比较简单,所以通常具有较低的通信开销和延迟。但不能绝对地说UDP一定比TCP传输得更快,因为应用程序如果在UDP上增加大量确认和重传机制,同样会产生额外开销。
使用场景方面,TCP适合对可靠性和完整性要求较高的业务,例如普通HTTP接口、数据库连接、文件传输和邮件。UDP适合更重视实时性、能够容忍少量数据丢失的场景,例如直播、语音通话、实时游戏和传统DNS查询。HTTP/3使用的QUIC也是建立在UDP之上,但QUIC在用户空间重新实现了可靠传输、多路复用和拥塞控制等机制。
如果面试时间较短,可以压缩成:
TCP面向连接,提供可靠、有序的字节流传输,通过序列号、ACK、重传、滑动窗口、流量控制和拥塞控制保证通信质量,但不保留消息边界,协议开销相对较大。UDP无连接,面向数据报,保留数据报边界,但协议本身不保证送达、顺序和去重,开销和连接延迟通常较小。TCP常用于接口、数据库和文件传输,UDP常用于DNS、直播、语音和游戏等场景。
这道题现在最需要补充的三个关键词是:
TCP:可靠、有序、字节流
UDP:尽力而为、数据报、有边界
性能:UDP通常更轻量,但不能绝对说一定更快
5. TCP三次握手的过程是什么?为什么是三次?
我答:
客户端先给服务器发送一个syn数据报,服务器返回一个ack应答报文,随后发出syn数据报,不过这两个过程一般很快,并且有延时应答和捎带应答的机制,所以会ack以及syn一起返回给客户端,最后客户端返回一个ack报文,这三次握手后算是正式的建立连接
ai打分,改错以及回答:
评分:55/100。
你已经正确说出了基本顺序:
SYN → SYN+ACK → ACK
-
"服务端先返回ACK,随后发送SYN"不够准确
在典型三次握手中,服务端直接发送一个
SYN+ACK报文,同时完成确认客户端SYN和发送自己SYN两件事。 -
与延迟应答、捎带应答无关
延迟ACK和捎带ACK主要是传输数据时减少单独ACK报文的优化机制。第二次握手将
SYN和ACK合并,是因为TCP报文可以同时设置这两个标志位。 -
没有说明序列号和确认号
三次握手真正同步的是双方的初始序列号,因此需要说出
seq=x、ack=x+1等信息。 -
基本没有回答"为什么是三次"
你说明了第二次可以把两个标志位放在一起,但没有解释为什么两次不够。
-
缺少握手双方的确认关系
第三次握手用于让服务端确认:客户端已经收到了服务端的SYN和初始序列号。
面试时可以这样回答:
TCP建立连接需要三次握手,主要目的是同步并确认通信双方的初始序列号。
第一次握手,客户端向服务端发送SYN报文,其中
SYN=1,seq=x,表示客户端请求建立连接,并将自己的初始序列号设置为x。第二次握手,服务端收到后返回一个
SYN+ACK报文,其中SYN=1,ACK=1,seq=y,ack=x+1。ack=x+1表示服务端确认收到了客户端的SYN,seq=y表示服务端向客户端发送自己的初始序列号。第三次握手,客户端收到后向服务端发送ACK报文,其中
ACK=1,ack=y+1,表示客户端已经收到并确认服务端的SYN。服务端收到这个ACK后,双方连接建立完成。之所以需要三次,是因为双方都需要发送自己的初始序列号,并确认对方已经收到。两次握手时,服务端无法确认客户端是否收到了服务端的SYN和初始序列号。四次握手可以完成,但没有必要,因为服务端对客户端SYN的ACK和服务端自己的SYN可以放在同一个报文中发送。
你的原答案可以直接改成:
客户端先向服务端发送SYN报文,并携带自己的初始序列号。服务端收到后返回SYN+ACK报文,一方面确认客户端的SYN,另一方面发送自己的初始序列号。客户端收到后再返回ACK,确认服务端的SYN,连接建立。三次握手是为了同步和确认双方的初始序列号。两次无法让服务端确认自己的SYN已经被客户端收到,四次没有必要,因为服务端的SYN和ACK可以合并发送。
你现在需要删掉这一段:
因为有延迟应答和捎带应答,所以ACK和SYN一起返回
改为:
服务端需要同时确认客户端的SYN并发送自己的SYN,
而TCP允许在一个报文中同时设置SYN和ACK标志位,
所以第二次握手使用SYN+ACK。
sqe就是32位序号
6. 三次握手中的报文丢失会怎样?
我答:
第一个syn丢失:客户端在长时间没有收到服务器返回的syn以及ack的时候,会进行超时重传;服务器返回的syn+ack丢失:客户端会重传syn,服务器会重传syn+ack;最后一个客户端的ack丢失:服务器重传syn+ack
ai打分,改错以及回答:
评分:82/100。
这次回答的三个结论基本都正确:
- 第一次
SYN丢失:客户端超时重传SYN。 - 第二次
SYN+ACK丢失:客户端和服务端都可能触发重传。 - 第三次
ACK丢失:服务端重传SYN+ACK。
主要不足如下:
-
"长时间没有收到"应该说成重传超时RTO
TCP不是随意等待一段时间,而是由重传定时器控制。
-
没有说明双方所处的连接状态
连接状态是这道题的重要追问点。
-
第三次ACK丢失后的过程没有说完
服务端重传
SYN+ACK后,客户端收到重复报文,会再次发送ACK。 -
没有说明重传不可能无限进行
超过系统规定的重试次数后,连接建立会失败,相关连接状态会被释放。
-
可以补充客户端提前发送数据的情况
第三次ACK丢失后,客户端已经认为连接建立。如果它发送带有有效ACK的数据,服务端也可能根据这个报文完成连接建立。
面试中可以这样回答:
三次握手中的三个报文都可能丢失,TCP会通过重传定时器处理,但不同报文丢失时,客户端和服务端的状态不同。
第一种情况是客户端发送的第一次SYN丢失。因为服务端根本没有收到SYN,所以服务端不会创建对应的半连接,也不会返回SYN+ACK。客户端处于
SYN-SENT状态,等待超过重传超时时间后,会重新发送SYN。超过最大重试次数仍然没有响应,客户端就会认为连接建立失败。第二种情况是服务端返回的SYN+ACK丢失。此时服务端已经收到客户端的SYN,处于
SYN-RECEIVED状态;客户端仍然处于SYN-SENT状态。客户端等待超时后会重传SYN,服务端等待不到最终ACK时,也会重传SYN+ACK。客户端最终收到SYN+ACK后,会发送第三次ACK。第三种情况是客户端发送的最终ACK丢失。客户端发送ACK后已经认为连接建立完成,可以进入
ESTABLISHED状态;但服务端没有收到ACK,仍然停留在SYN-RECEIVED状态。服务端等待超时后会重传SYN+ACK,客户端收到重复的SYN+ACK后,会再次发送ACK,服务端收到后进入ESTABLISHED状态。另外,如果最终ACK丢失后客户端直接发送业务数据,这个TCP报文通常也会携带有效ACK。服务端验证确认号正确后,也可能完成连接建立并处理数据。
三种情况可以记成:
第一次SYN丢失:
客户端超时 → 重传SYN
第二次SYN+ACK丢失:
客户端可能重传SYN
服务端也可能重传SYN+ACK
第三次ACK丢失:
服务端重传SYN+ACK
客户端再次发送ACK
对应状态:
第一次SYN丢失:
客户端:SYN-SENT
服务端:不知道这次连接
SYN+ACK丢失:
客户端:SYN-SENT
服务端:SYN-RECEIVED
最后ACK丢失:
客户端:ESTABLISHED
服务端:SYN-RECEIVED
你原来的答案可以稍微修改成:
第一次SYN丢失时,服务端没有收到连接请求,客户端处于SYN-SENT状态,并在重传超时后重新发送SYN。SYN+ACK丢失时,客户端可能因为收不到响应而重传SYN,服务端也可能因为收不到最终ACK而重传SYN+ACK。第三次ACK丢失时,客户端已经进入ESTABLISHED状态,服务端仍处于SYN-RECEIVED状态,因此服务端会重传SYN+ACK,客户端收到后再次发送ACK。重传超过规定次数后,连接建立失败。
7. TCP为什么通常四次挥手?
我答:
TCP挥手过程是要解除联系的一方进行发送FIN报文,然后另一方返回ack,在返回完ack之后,还有可能去进行一些其他的操作,这些操作会需要花费一些时间,所以这里的ack和FIN是不一定会一起返回的,然后最后发起方在收到FIN之后会返回一个ack,所以总共的操作一般是四步
ai打分,改错以及回答:
评分:80/100。
你的核心理解是正确的:接收方收到FIN后,通常先返回ACK,但它自己可能还有数据没有发送完,因此不能马上发送FIN。等剩余数据处理完成后再发送FIN,所以通常形成四个报文。
主要不足如下:
-
没有说明TCP是全双工通信
这是"为什么通常需要四次"的根本原因。TCP两个方向的数据传输需要分别关闭。
-
FIN不是直接解除整个连接
一方发送FIN只表示:
我这个方向没有数据要发送了。
对方仍然可以继续向它发送数据,这叫半关闭状态。
-
"进行一些其他操作"过于模糊
应该明确说:接收方的应用程序可能还有数据需要发送,或者还没有调用关闭连接的方法。
-
ACK和FIN不是绝对分开发送
如果接收方收到FIN时自己也没有剩余数据,可以把ACK和FIN合并,因此也可能只看到三个报文。
-
可以补充双方状态变化
面试官经常继续追问
FIN-WAIT、CLOSE-WAIT和TIME-WAIT。
面试时可以这样回答:
TCP通常需要四次挥手,是因为TCP是全双工协议,两个方向的数据传输可以独立进行,因此两个方向也需要分别关闭。
第一次挥手,主动关闭方发送FIN报文,表示自己已经没有数据需要发送了,但仍然可以接收对方的数据。
第二次挥手,被动关闭方收到FIN后先返回ACK,表示已经收到关闭请求。此时只是主动关闭方到被动关闭方这个方向被关闭,被动关闭方仍然可以继续发送剩余数据。
等被动关闭方把剩余数据发送完成,并且它的应用程序也决定关闭连接时,会进行第三次挥手,向主动关闭方发送自己的FIN。
第四次挥手,主动关闭方收到FIN后返回ACK。被动关闭方收到最终ACK后关闭连接,主动关闭方进入TIME_WAIT状态,等待一段时间后再完全关闭。
因此,四次挥手的根本原因是两个方向需要分别关闭。被动关闭方对第一个FIN的ACK由TCP协议栈确认,而什么时候发送自己的FIN,取决于本地应用什么时候完成剩余数据并关闭连接,所以ACK和FIN通常不能立即合并。
如果被动关闭方收到FIN时刚好也没有剩余数据需要发送,ACK和FIN也可以合并,因此实际可能只出现三个报文。
8. TIME_WAIT和CLOSE_WAIT分别是什么?
我答:
TIME_WAIT发起解除连接的一方有的状态,在双方都发完FIN之后,就进入这个状态,表示双方也没有消息要发了,只等我这边最后一个ack发完就结束连接,CLOSE_WAIT是接收解除连接一方在对方发送FIN报文之后会进入的状态,直到我自己这一方也没有消息要发了,才会转换状态
ai打分,改错以及回答:
评分:70/100。
你的核心方向基本正确:
TIME_WAIT通常出现在主动关闭方。CLOSE_WAIT出现在收到对方FIN的一方。CLOSE_WAIT期间,本地仍然可以继续发送数据。
不过两个状态的进入时间和退出条件还需要修正。
主要不足如下:
-
TIME_WAIT是在最终ACK发送之后进入的
不是"等待把最后一个ACK发出去"。主动关闭方收到对方FIN并发送最终ACK后,才进入
TIME_WAIT。 -
进入TIME_WAIT后不会立即结束连接
它还需要等待
2MSL,然后才能进入CLOSED。 -
没有说明TIME_WAIT的两个作用
- 最终ACK丢失时,可以重新确认对方重传的FIN。
- 等待旧连接中的延迟报文从网络中消失。
-
CLOSE_WAIT不是等到"自己没有消息要发"就自动转换
它需要本地应用程序主动调用
close()等关闭操作。应用不关闭,连接可能一直停留在CLOSE_WAIT。 -
CLOSE_WAIT之后通常进入LAST_ACK
本地应用关闭连接并发送FIN后,会从
CLOSE_WAIT进入LAST_ACK,等待对方最终确认。
面试中可以这样回答:
TIME_WAIT和CLOSE_WAIT分别出现在TCP连接关闭过程的不同一方。
TIME_WAIT通常出现在主动关闭连接的一方。主动关闭方发送自己的FIN,收到对方ACK后继续等待。当它收到对方的FIN并返回最后一个ACK后,就会进入TIME_WAIT状态。它不会立即关闭,而是等待2MSL后才进入CLOSED状态。
TIME_WAIT主要有两个作用。第一,如果最后一个ACK丢失,被动关闭方会重新发送FIN,主动关闭方仍然保留连接状态,因此可以再次返回ACK。第二,让旧连接中可能延迟到达的报文在网络中消失,避免影响后续使用相同四元组建立的新连接。
CLOSE_WAIT出现在被动关闭连接的一方。当本机收到对方的FIN并返回ACK后,会进入CLOSE_WAIT。这个状态表示对方已经不再发送数据,但本机应用程序可能还有数据需要发送,因此连接还不能完全关闭。等本地应用程序处理完剩余数据并主动调用关闭操作后,本机发送自己的FIN,从
CLOSE_WAIT进入LAST_ACK。收到对方最终ACK后,连接才进入CLOSED。如果服务器上出现大量长期存在的
CLOSE_WAIT,通常说明应用程序没有正确关闭Socket、流或者HTTP响应资源;大量TIME_WAIT则经常与大量短连接或者主动关闭连接有关,不一定代表程序存在资源泄漏。
9. TCP如何保证可靠传输?
我答:
通过TCP的两个核心机制:确认应答和超时重传,确认应答是为了保证对方收到了我发出去的消息,就TCP不是面向字节流的嘛,所以会对数据进行编号,假设我们发送了0-2000的数据,对方如果收到了消息,就会返回一个带有2001的ack报文,表示对方已经收到了0-2000的数据,并且期待2001开始的数据,超时重传是当我们发送一个数据之后,却迟迟等不到对方的ack报文,这个时候我们会等一会,等到一定时间之后,会进行一个重传,意思是这个数据可能丢失了或者咋了,对方没后收到,需要我们重新传一份,并且我们收到的数据会现在对方的缓存中,进行一个数据的排序以及数据的去重,主要也就可以保证如果数据是因为传输速率太慢了,等到我们重传以后居然传到对方的情况
ai打分,改错以及回答:
评分:78/100。
你的主线基本正确:序列号、确认应答、超时重传、排序和去重都讲到了,已经能说明 TCP 可靠传输的大部分原理。
主要不足如下:
-
TCP 不只依靠确认应答和超时重传
还包括校验和、序列号、累计确认、快速重传、接收窗口等机制。面试中只说两个核心机制,会显得不够完整。
-
ACK 的含义需要说得更严谨
ACK=2001表示:序号小于2001的字节都已经收到,下一步期望收到序号为2001的字节。如果发送的是序号
0~2000,一共正好是2001字节,那么返回ACK=2001是正确的。 -
超时不一定表示数据报文丢失
还可能是:
- 数据到达,但ACK丢失;
- 数据或ACK在网络中延迟;
- 网络拥塞导致往返时间变长。
因此应该说"发送方在规定时间内没有收到确认,于是认为本次传输可能失败并重传"。
-
缺少快速重传
TCP不一定非要等到超时。如果发送方连续收到多个重复ACK,通常可以判断中间某一段数据丢失,提前重传。
-
"传输速度太慢所以重传"表达不准确
TCP依据的是重传计时器是否超时,而不是简单判断网速快慢。网络延迟突然增大确实可能触发不必要的重传,但TCP会根据往返时间动态计算重传超时时间。
面试时,我建议你这样回答:
TCP主要通过校验和、序列号、确认应答、超时重传、快速重传以及接收窗口等机制保证可靠传输。
首先,TCP会给传输的字节编号。接收方根据序列号判断数据是否完整、是否重复,并且可以把乱序到达的数据重新排列。TCP首部中的校验和可以帮助接收方检测数据在传输过程中是否发生错误。
接收方收到数据后,会向发送方返回ACK。ACK确认号表示接收方下一次期望收到的字节序号。例如,接收方已经连续收到了序号0到2000的字节,就可以返回
ACK=2001。如果发送方在重传超时时间内没有收到相应的ACK,就会重新发送尚未被确认的数据。不过,超时可能是数据丢失,也可能是ACK丢失或者网络延迟过大。
TCP还支持快速重传。当发送方连续收到多个相同的重复ACK时,可以推测某一段数据丢失,从而不等计时器超时就进行重传。
此外,TCP使用接收窗口进行流量控制,避免发送方发送得太快导致接收方来不及处理;拥塞控制则用于避免向网络注入过多数据。这些机制共同实现了可靠、有序、无重复的字节流传输。
10. 流量控制和拥塞控制有什么区别?
我答:
流量控制是对于接收方来说的,就是由于TCP的相对效率较低,所以有一个滑动窗口的机制可以适当增加效率,可以一次性发送多组数据,像一个窗口一样受到对应ack回复就往后滑,但是过多的数据一起可能会导致接收方处理不过来,导致数据阻塞在那,所以为了缓解这种方法,我们有了流量控制,就是会告诉对方我缓冲区的剩余空间大小,让对方控制一下发送的数据量;拥塞控制是对于网络的一种控制,就是数据在网络传输的时候会很复杂,可能性很多,很可能多组数据都要通过同一个路由器设备进行转发呢,所以我们得对这个数据量进行一个控制,并且我们先认定所有网络路线为一个整体,我们通过试一试的方式来判定网络承受数据的能力,来确定一个拥塞窗口,我们也有一个大小变化图,先缓慢增长,之后线性增长,等到了阈值之后就进行一个指数增长,直到到达承受能力的上限,就是到达丢包的时候,然后我们的大小变为阈值的一般,再进行线性增长,然后一点一点去改变,因为网络的复杂性,所以窗口大小也是一直动态变化的,我们通过流量控制的窗口大小和拥塞控制的窗口大小的较小值来决定的滑动窗口的大小
ai打分,改错以及回答:
评分:72/100。
你已经说出了最重要的区别:流量控制保护接收方,拥塞控制保护网络,也知道最终发送窗口取两个窗口的较小值。但拥塞窗口的变化过程说反了,这是本题主要扣分点。
主要不足如下:
-
流量控制不是因为"TCP效率较低"
流量控制解决的是:发送方发送太快,接收方的缓冲区和处理能力跟不上。
-
真正发送数据的是发送方
接收方通过TCP首部中的窗口字段告诉发送方自己的剩余接收能力,这个窗口叫
rwnd。发送方根据它限制未确认数据量。 -
慢启动和拥塞避免的顺序说反了
经典面试模型中:
- 开始时执行慢启动,
cwnd近似每经过一个RTT翻倍,即指数增长; - 达到慢启动阈值
ssthresh后,进入拥塞避免,cwnd近似线性增长; - 检测到丢包后,降低拥塞窗口。
- 开始时执行慢启动,
-
不能说"达到网络承受能力上限就是丢包"
TCP并不知道网络的准确上限,只能根据丢包、重复ACK、超时或ECN等信号,推测网络可能发生了拥塞。
-
丢包后的处理需要区分情况
在经典TCP Reno模型中:
- 发生超时:认为拥塞比较严重,
cwnd大幅降低,然后重新慢启动; - 收到3个重复ACK:执行快速重传和快速恢复,窗口通常不会直接降到最小。
- 发生超时:认为拥塞比较严重,
-
"先缓慢增长,然后线性增长"不准确
慢启动虽然名字里有"慢",但它的窗口增长其实比较快,是指数增长。"慢"是相对于一开始就把大量数据注入网络而言。
面试时可以这样回答:
流量控制和拥塞控制限制的对象不同。流量控制是为了防止发送方发送得太快,导致接收方来不及处理;拥塞控制是为了防止发送方向网络中注入过多数据,导致路由器队列堆积、延迟增大甚至丢包。
流量控制主要通过接收窗口
rwnd实现。接收方会根据接收缓冲区的剩余空间,在ACK报文的窗口字段中通告自己还能接收多少数据。发送方根据这个值限制未确认数据的数量。如果接收方缓冲区快满了,就通告一个较小的窗口;如果窗口变成0,发送方会暂时停止发送普通数据。拥塞控制主要通过发送方维护的拥塞窗口
cwnd实现。发送方并不知道网络的准确容量,只能根据ACK、丢包、超时等现象推测网络是否拥塞。在经典TCP拥塞控制模型中,开始时通过慢启动让cwnd指数增长;达到慢启动阈值后进入拥塞避免,让窗口近似线性增长。如果检测到丢包,就减小拥塞窗口。最终,发送方能够发送但尚未确认的数据量,同时受到接收窗口和拥塞窗口限制,所以实际发送窗口通常可以表示为:
发送窗口 = min(rwnd, cwnd)其中,
rwnd反映接收方的处理能力,cwnd反映发送方当前估计的网络承载能力。
经典变化过程可以记成:
开始连接
↓
慢启动:cwnd指数增长
↓ 达到ssthresh
拥塞避免:cwnd近似线性增长
↓ 检测到丢包
减小cwnd,并根据丢包方式继续调整
12. TCP报文头包含哪些重要字段?
我答:
16位源端口,16位目的端口,32位序号,32位确认序号,4位首部长度,保留位,标志位,这个标志位里面有确认应答的报文,建立连接断开连接的报文,复位报文,紧急指针有效的报文,还有催促的报文,还有16位窗口大小,16位校验和以及16位紧急指针
ai打分,改错以及回答:
评分:76/100。
你基本记住了TCP首部的主要字段及位数,说明基础结构掌握得不错。主要问题是:列出了字段,却没有充分说明字段的作用;标志位的名称和表达也不够准确。
主要不足如下:
-
没有提到"选项"和"填充"字段
TCP选项很重要,常见内容包括MSS、窗口扩大、SACK和时间戳。因为存在选项,所以TCP首部长度并不固定。
-
首部长度字段需要说明单位
首部长度占4位,单位是4字节。TCP首部最少20字节,最多60字节。
-
标志位应直接说出名称
面试中至少应说出:
SYN:建立连接并同步初始序列号;ACK:确认号字段有效;FIN:发送方没有数据要发送,请求关闭这一方向的连接;RST:异常复位连接;PSH:提示接收端尽快向应用程序交付数据;URG:紧急指针字段有效。
其中"催促报文"并不是规范说法,应该说
PSH标志。 -
窗口大小应说明用途
这个字段表示接收方当前通告的接收窗口
rwnd,用于TCP流量控制。 -
校验和应说明校验范围
TCP校验和用于发现传输错误,计算时包括IP伪首部、TCP首部和TCP数据。
面试时可以这样回答:
TCP首部最少20字节,包含源端口、目的端口、序列号、确认号、首部长度、标志位、窗口大小、校验和、紧急指针以及可选字段等。
源端口和目的端口各占16位,用于标识通信双方的应用进程。序列号和确认号各占32位,序列号表示本报文段数据的第一个字节序号,确认号表示接收方下一次期望收到的字节序号。
首部长度占4位,单位是4字节。因为TCP可能携带可变长度的选项,所以接收方需要通过这个字段确定数据从哪里开始。TCP首部最少20字节,最多60字节。
常见标志位包括
SYN、ACK、FIN、RST、PSH、URG。SYN用于建立连接并同步初始序列号,ACK表示确认号有效,FIN用于关闭一个方向的连接,RST用于异常复位连接,PSH提示接收端尽快把数据交给应用程序,URG表示紧急指针有效。此外,还有与显式拥塞通知有关的ECE和CWR等标志位。窗口大小字段表示接收方通告的接收窗口,用于流量控制。校验和用于检查TCP首部和数据是否发生错误。紧急指针需要配合
URG使用。TCP还可以携带选项,例如MSS、窗口扩大因子、SACK和时间戳,最后通过填充字段保证TCP首部长度是4字节的整数倍。
可以按功能记忆:
找到应用:源端口、目的端口
可靠传输:序列号、确认号、校验和
连接控制:SYN、ACK、FIN、RST等标志位
流量控制:窗口大小
扩展能力:选项和填充
13. TCP粘包和拆包为什么出现?怎么解决?
我答:
因为TCP是面向字节流的协议,所以不像UDP一样是一份数据报一份数据报的发,而是一连串的数据跟水流一样的发送出去,那对方拿到就是所有数据堆在一起,没办法区分开来,这就是我们常说的粘包问题,一组一组的数据粘在一起没办法区分开来,那如何解决呢,我们可以通过在一组数据的末尾设置一个标志位,一般是用特殊的符号来好区分一点,或者是在数据的头部设置一个属性,记录这组数据的大小,这样也可以区分开;拆包是因为一组数据可能太长了,没办法一次性发送过去,所以我们会对数据进行一个拆包,将数据分为一份一份的发过去,然后在完整到达对面之后进行一个组包
ai打分,改错以及回答:
评分:82/100。
你正确说出了:
- TCP是面向字节流的;
- TCP不保留应用层消息边界;
- 多条消息可能粘在一起;
- 一条消息可能被分成多次传输或读取;
- 可以使用分隔符或长度字段解决。
主要不足如下:
-
拆包不一定是因为数据"太长"
数据较长、超过MSS时确实会被TCP分段,但即使一条消息很短,接收方一次
read()也不保证将它完整读出。操作系统缓冲区、网络传输和线程调度都可能让一条消息分多次读取。 -
"发送方主动对数据拆包"不够准确
应用程序通常只是把字节写入TCP连接,具体如何分成TCP报文段,主要由TCP协议栈处理。应用程序不应该依赖TCP报文段来判断业务消息的边界。
-
"完整到达后组包"需要区分两层
TCP协议栈负责按照序列号重传、排序并向应用层提供连续字节流;应用层负责按照自己设计的协议,从字节流中解析出一条条完整消息。
-
"标志位"最好改成"分隔符"
"标志位"容易让面试官误以为你在说TCP首部中的
SYN、ACK、FIN。这里应该说消息结束符或分隔符。
面试时可以这样回答:
TCP粘包和拆包的根本原因是TCP面向字节流,它只保证字节可靠、有序地到达,不保留应用层消息的边界,因此发送方一次写入和接收方一次读取之间没有一一对应关系。
粘包是指接收方一次读取到了多条应用层消息,例如发送方连续发送
ABC和DEF,接收方可能一次读取到ABCDEF。拆包是指一条应用层消息需要经过多次读取才能完整获得。例如发送方发送
ABCDEF,接收方可能先读取到ABC,随后才读取到DEF。数据较长导致TCP分段可能造成这种现象,但即使消息很短,也不能保证一次读取就能完整获得。解决这个问题需要在应用层设计消息边界。常见方案有三种:第一种是规定每条消息的固定长度;第二种是在消息末尾添加分隔符,例如换行符;第三种是在消息头中记录消息体长度,接收方先解析长度,再读取指定数量的字节。实际项目中,消息头加消息体长度的方式比较常见。
接收方还需要维护缓冲区:数据不足一条消息时继续等待,够一条消息时进行解析,如果缓冲区中包含多条消息,就循环解析。
例如发送两条消息:
发送方写入:ABC | DEF
接收方读取结果可能是:
ABCDEF 粘在一次读取中
ABC、DEF 恰好分成两次读取
AB、CDE、F 出现跨消息的拆分
你的回答只需要把这句话:
"一组数据太长,无法一次发送,所以我们会对数据进行拆包。"
改为:
"一条应用层消息可能被TCP分成多个报文段传输,也可能由于接收缓冲区和读取时机的不同,需要经过多次读取才能完整获得。"
一句话记忆:
TCP负责提供可靠有序的字节流,应用层负责通过定长、分隔符或长度字段划分消息边界。
它这里讲到的MSS和数据链路层的协议有关,比如以 以太网为例,一个ip数据包一般最大是1500字节,然后减去ip首部以及tcp首部,得到的就是tcp可携带数据的大小
后话
之后继续将网络的部分补充完整,那个时候就会补充包含http的面试题,敬请期待。。。。