计算机网络面试

警告
本文最后更新于 2022-09-09,文中内容可能已过时。

在计算机网络要做到有条不紊地交换数据,就必须遵守一些事先约定好的规则,比如交换数据的格式、是否需要发送一个应答信息。这些规则被称为网络协议。

  • TCP/IP:四层。应用层(Application)、传输层(Transport)、网际层(Internet)、网络接口层(Network Access)。
  • OSI:七层。应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层 (Network)、数据链路层(Data Link)、物理层(Physical)。

优点:

  1. 简化问题难度和复杂度。由于各层之间独立,我们可以分割大问题为小问题。
  2. 灵活性好。当其中一层的技术变化时,只要层间接口关系保持不变,其他层不受影响。
  3. 易于实现和维护。
  4. 促进标准化工作。分开后,每层功能可以相对简单地被描述。

缺点:

  1. 功能可能出现在多个层里,产生了额外开销。
  2. 开放系统互联基本参考模型(OSI/RM),简称为 OSI,其概念清楚,理论也较完整,但既复杂又不实用。

应用层(Application Layer)的任务是通过应用进程间的交互来完成特定网络应用。应用层协议定义的是应用进程(进程:主机中正在运行的程序)间的通信和交互的规则。

对于不同的网络应用需要不同的应用层协议。在互联网中应用层协议很多,如域名系统 DNS,支持万维网应用的 HTTP 协议,支持电子邮件的 SMTP 协议等。

基于 TCP 的协议:

  • HTTP(Hypertext Transfer Protocol,超文本传输协议),主要用于普通浏览。
  • HTTPS(HTTP over SSL,安全超文本传输协议),HTTP 协议的安全版本。
  • FTP(File Transfer Protocol,文件传输协议),文件传输。
  • POP3(Post Office Protocol version 3,邮局协议),收邮件。
  • SMTP(Simple Mail Transfer Protocol,简单邮件传输协议),发邮件。
  • SSH(Secure Shell,用于替代安全性差的 TELNET),用于加密安全登陆用。
  • TELNET(Teletype over the Network,网络电传),通过一个终端(terminal)登陆到网络。

基于 UDP 的协议:

  • DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),动态配置IP地址。

基于 TCP 和 UDP 的协议:

  • DNS(Domain Name System,域名系统),根据域名查找 IP。

传输层(Transport Layer)的主要任务就是负责向两台主机进程之间的通信提供通用的数据传输服务。应用进程利用该服务传送应用层报文。主要使用 TCP 和 UDP 两种协议。

  1. TCP(Transmission Control Protocol,传输控制协议):提供面向连接的,可靠的数据传输服务。
  2. UDP(User Datagram Protocol,用户数据报协议):提供无连接的,尽大努力的数据传输服务(不保证数据传输的可靠性)。
UDPTCP
是否连接无连接面向连接
是否可靠不可靠传输可靠传输,使用流量控制和拥塞控制
连接对象个数支持一对一、一对多、多对一和多对多交互通信一对一通信
传输方式面向报文面向字节流
首部开销首部8B首部20B-60B
适用场景适用于实时应用(IP电话、视频会议、直播等)适用于要求可靠传输的应用,例如文件传输

网际层(Internet Layer)的任务就是选择合适的网间路由和交换结点,确保计算机通信的数据及时传送。在发送数据时,网络层把传输层产生的报文段或用户数据报封装成分组和包进行传送。

在 TCP/IP 体系结构中,由于网际层使用 IP(Internet Protocol,网际协议)协议,因此分组也叫 IP 数据报,简称数据报。

互联网是由大量的异构(Heterogeneous)网络通过路由器(Router)相互连接起来的。互联网使用的网络层协议是无连接的 IP 协议和许多路由选择协议,因此互联网的网络层也叫做网际层或 IP 层。

数据链路层(Data Link Layer)通常简称为链路层。两台主机之间的数据传输,总是在一段一段的链路上传送的,这就需要使用专门的链路层的协议。

在两个相邻节点之间传送数据时,数据链路层将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。每一帧包括数据和必要的控制信息(如同步信息,地址信息,差错控制等)

在接收数据时,控制信息使接收端能够知道一个帧从哪个比特开始和到哪个比特结束。

web 应用的通信传输流

web 应用的通信传输流

发送端在上层向下层传输数据时,每经过一层时会添加一个该层所属的首部信息。反之,接收端在下层向上层传输数据时,每经过一层时会把对应该层的首部信息去除,只传输数据。

在物理层上所传送的数据单位是比特。物理层(Physical Layer)的作用是实现相邻计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。使其上面的数据链路层不必考虑网络的具体传输介质是什么。

比特流的透明传送:表示经实际电路传送后的比特流没有发生变化,对传送的比特流来说,这个电路好像是看不见的。

TCP 是一种面向连接的、可靠的、基于字节流的传输层通信协议,在发送数据前,通信双方必须在彼此间建立一条连接。

所谓的“连接”,其实是客户端和服务端保存的一份关于对方的信息,如 ip 地址、端口号等。

TCP 可以看成是一种字节流,它会处理网际层或更低层的丢包、重复以及错误问题。

在连接的建立过程中,双方需要交换一些连接的参数。这些参数可以放在 TCP 头部。

一个 TCP 连接由一个 4 元组构成,分别是两个 ip 地址和两个端口号。

一个 TCP 连接通常分为三个阶段:连接、数据传输、退出(关闭)。

通过三次握手建立一个链接,通过四次挥手来关闭一个连接。

当一个连接被建立或被关闭时,交换的报文段只包含 TCP 头部,而没有数据。

TCP 报文的头部结构

TCP 报文的头部结构

  • 序号(Sequence Number,seq):32 bit,4B,用来标识从 TCP 源端向目的端发送的字节流,发起方发送数据时对此进行标记。
  • 确认序号(Acknowledgement Number,ack):32 bit,4B,只有 ACK 标志位置为 1 时,确认序号字段才有效,确认方ack=发送方seq+1
  • 标志位:1 bit,6 个共 6 bit。
    • URG(urgent):紧急指针(Urgent Pointer)有效。
    • ACK(acknowledgment):确认序号有效。
    • PSH(push):接收方应该尽快将这个报文交给应用层。
    • RST(reset):重置连接。
    • SYN(synchronize):发起一个新连接。
    • FIN(finish):释放一个连接。

三次握手的本质是确认通信双方接收和发送数据的能力。

  1. 握手前。我不知道我能否发送和接收数据;对方也不知道他能否发送和接收数据。
  2. 第一次握手。我发送数据,对方收到,则对方知道我能发送数据,他自己能接收数据。
  3. 第二次握手。对方发送数据,他告诉我收到了我之前发送的数据,我收到,则我知道对方能发送和接收数据,我自己能发送和接收数据。
  4. 第三次握手。我发送数据,我告诉对方收到了他之前发送的数据,对方收到,则对方知道我能发送和接收数据,他自己能发送和接收数据。
  5. 握手后。双方都确认对方能够发送和接收数据,自己也能够发送和接收数据。连接建立。
TCP 建立连接的三次握手

TCP 建立连接的三次握手

  1. 第一次握手。客户端向服务端发起连接请求,首先客户端随机生成一个起始序列号 ISN(假设 100),那客户端向服务端发送的报文段 SYN=1,seq=100。
  2. 第二次握手。服务端收到客户端发过来的报文后,发现 SYN=1,知道这是一个连接请求,于是将客户端的起始序列号 100 存起来,并且随机生成一个服务端的起始序列号(假设 300)。然后给客户端回复一段报文,回复报文段 SYN=1、ACK=1、seq=300、ack=101(客户端seq + 1)。
  3. 第三次握手。客户端收到服务端的回复后发现 ACK=1、ack=101,于是知道服务端已经收到了序列号为 100 的报文;同时发现 SYN=1,知道了服务端同意了这次连接,于是就将服务端的起始序列号 300 保存下来。然后客户端再回复一段报文给服务端,报文 ACK=1、ack=301(服务端seq + 1)、seq=101(第一次握手时发送报文是占据一个序列号的,所以这次 seq 就从 101 开始)。当服务端收到报文后发现 ACK=1、ack=301,就知道客户端已经收到序列号为 300 的报文,就这样客户端和服务端就通过 TCP 建立了连接。

不携带数据的 ACK 报文是不占据序列号的,所以后面第一次正式发送数据时 seq 还是 101。

四次挥手的本质是确认通信双方是否想关闭连接

  1. 挥手前。双方可以互相发送数据。
  2. 第一次挥手。我发送数据,告诉对方我想要关闭连接,对方收到,则对方知道我想关闭连接,且我已经准备好关闭连接。
  3. 第二次挥手。对方发送数据,告诉我收到了我之前发送的数据,我收到,但我不知道对方是否想关闭连接。
  4. 第三次挥手。对方发送数据,告诉我他也想要关闭连接,我收到,则我知道了对方也想关闭连接,因此我正式关闭连接。
  5. 第四次挥手。我发送数据,告诉对方收到了他之前发送的数据,对方收到,则对方知道了我知道他也想关闭连接,因此对方正式关闭连接。
  6. 挥手后。连接关闭。
TCP 关闭连接的四次挥手

TCP 关闭连接的四次挥手

比如客户端初始化的序列号ISA=100,服务端初始化的序列号ISA=300。TCP连接成功后客户端总共发送了1000个字节的数据,服务端在客户端发FIN报文前总共回复了2000个字节的数据。

  1. 第一次挥手:当客户端的数据都传输完成后,客户端向服务端发出连接释放报文(当然数据没发完时也可以发送连接释放报文并停止发送数据),释放连接报文包含FIN标志位 (FIN=1)、序列号seq=1101(100+1+1000,其中的1是建立连接时占的一个序列号)。需要注意的是客户端发出FIN报文段后只是不能发数据了,但是还可以正常收数据;另外 FIN报文段即使不携带数据也要占据一个序列号。
  2. 第二次挥手:服务端收到客户端发的FIN报文后给客户端回复确认报文,确认报文包含ACK标志位(ACK=1)、确认号ack=1102(客户端FIN报文序列号1101+1)、序列号 seq=2300(300+2000)。此时服务端处于关闭等待状态,而不是立马给客户端发FIN报文,这个状态还要持续一段时间,因为服务端可能还有数据没发完。
  3. 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、 序列号seq=2350(2300+50)。
  4. 第三次挥手:服务端将最后数据(比如50个字节)发送完毕后就向客户端发出连接释放报文,报文包含FIN和ACK标志位(FIN=1,ACK=1)、确认号和第二次挥手一样ack=1102、 序列号seq=2350(2300+50)。

因为需要考虑连接时丢包的问题,如果只握手2次,第二次握手时如果服务端发给客户端的确认报文段丢失,此时服务端已经准备好了收发数(可以理解服务端已经连接成功)据, 而客户端一直没收到服务端的确认报文,所以客户端就不知道服务端是否已经准备好了(可以理解为客户端未连接成功),这种情况下客户端不会给服务端发数据,也会忽略服务端 发过来的数据。 如果是三次握手,即便发生丢包也不会有问题,比如如果第三次握手客户端发的确认ack报文丢失,服务端在一段时间内没有收到确认ack报文的话就会重新进 行第二次握手,也就是服务端会重发SYN报文段,客户端收到重发的报文段后会再次给服务端发送确认ack报文。

因为只有在客户端和服务端都没有数据要发送的时候才能断开TCP。而客户端发出FIN报文时只能保证客户端没有数据发了,服务端还有没有数据发客户端是不知道的。而服务端 收到客户端的FIN报文后只能先回复客户端一个确认报文来告诉客户端我服务端已经收到你的FIN报文了,但我服务端还有一些数据没发完,等这些数据发完了服务端才能给客户 端发FIN报文(所以不能一次性将确认报文和 FIN报文发给客户端,就是这里多出来了一次)。

这里同样是要考虑丢包的问题,如果第四次挥手的报文丢失,服务端没收到确认 ack报文就会重发第三次挥手的报文,这样报文一去一回 长时间就是2MSL,所以需要等这么长时间来确认服务端确实已经收到了。

TCP设有一个保活计时器,客户端如果出现故障,服务器不能一直等下去,白白浪费资源。服务器每收到一次客户端的请求后都会重新复位这个计时器,时间通常是设置为2小时,若两小时还没有收到客户端的任何数据,服务器就会发送一个探测报文段,以后每隔75秒钟发送一次。若一连发送10个探测报文仍然没反应,服务器就认为客户端出了故障,接着就关闭连接。

HTTP 状态码表示客户端 HTTP 请求的返回结果、标识服务器处理是否正常、表明请求出现的错误等。

  • 1XX:Informational(信息性),接受的请求正在处理。
    • 100:Continue(继续)。
    • 101:Switching Protocol(切换协议)。
  • 2XX:Success(成功),请求正常处理完毕。
    • 200:OK(成功),表示从客户端发来的请求在服务器端被正确处理。
    • 201:Created(已创建)。
    • 202:Accepted(已创建)。
    • 203:Non-Authoritative Information(未授权信息)。
    • 204:No Content(无内容),表示请求成功,但响应报文不含实体的主体部分。
    • 205:Reset Content(重置内容)。
    • 206:Partial Content(部分内容),进行范围请求成功。
  • 3XX:Redirection(重定向),需要进行附加操作以完成请求。(对于 301/302/303 状态码,几乎所有浏览器都会删除报文主体并自动用 GET 方法重新请求)
    • 300:Multiple Choice(多种选择)。
    • 301:Moved Permanently(永久移动),永久性重定向,表示资源已被分配了新的 URL。
    • 302:Found(临时移动),临时性重定向,表示资源临时被分配了新的 URL。
    • 303:See Other(查看其他位置),表示资源存在着另一个 URL,应使用 GET 方法获取资源。
    • 304:Not Modified(未修改),表示服务器允许访问资源,但请求未满足条件的情况(与重定向无关)。
    • 305:Use Proxy(使用代理)。
    • 306:Unused(未使用)。
    • 307:Temporary Redirect(临时重定向),临时性重定向,和 302 类似,但是期望客户端保持请求方法不变向新的地址发出请求。
    • 308:Permanent Redirect(永久重定向)。
  • 4XX:Client Error(客户端错误),服务器无法处理请求。
    • 400:Bad Request(错误请求),请求报文存在语法错误。
    • 401:Unauthorized(未授权),表示发送的请求需要有通过 HTTP 认证的认证信息。
    • 402:Payment Required(需要付款)。
    • 403:Forbidden(禁止访问),表示对请求资源的访问被服务器拒绝,可在实体主体部分返回原因描述。
    • 404:Not found(未找到),表示在服务器上没有找到请求的资源。
    • 405:Method Not Allowed(不允许使用该方法)。
    • 406:Not Acceptable(无法接受)。
    • 407:Proxy Authentication Required(要求代理身份验证)。
    • 408:Request Timeout(请求超时)。
    • 409:Conflict(冲突)。
    • 410:Gone(已失效)。
    • 411:Length Required(需要内容长度头)。
    • 412:Precondition Failed(预处理失败)。
    • 413:Request Entity Too Large(请求实体过长)。
    • 414:Request-URI Too Long(请求网址过长)。
    • 415:Unsupported Media Type(媒体类型不支持)。
    • 416:Requested Range Not Satisfiable(请求范围不合要求)。
    • 417:Expectation Failed(预期结果失败)。
  • 5XX:Server Error(服务器错误),服务器处理请求出错。
    • 500:Internal Sever Error(内部服务器错误),表示服务器端在执行请求时发生了错误。
    • 501:Not Implemented(未实现),表示服务器不支持当前请求所需要的某个功能。
    • 502:Bad Gateway(网关错误)。
    • 503:Service Unavailable(服务不可用),表明服务器暂时处于超负载或正在停机维护,无法处理请求。
    • 504:Gateway Timeout(网关超时)。
    • 505:HTTP Version Not Supported(HTTP 版本不受支持)。

GET 和 POST

说到GET和POST,就不得不提HTTP协议,因为浏览器和服务器的交互是通过HTTP协议执行的,而GET和POST也是HTTP协议中的两种方法。

HTTP全称为Hyper Text Transfer Protocol,中文翻译为超文本传输协议,目的是保证浏览器与服务器之间的通信。HTTP的工作方式是客户端与服务器之间的请求-应答协议。

HTTP协议中定义了浏览器和服务器进行交互的不同方法,基本方法有4种,分别是GET,POST,PUT,DELETE。这四种方法可以理解为,对服务器资源的查,改,增,删。

  • GET:从服务器上获取数据,也就是所谓的查,仅仅是获取服务器资源,不进行修改。
  • POST:向服务器提交数据,这就涉及到了数据的更新,也就是更改服务器的数据。
  • PUT:英文含义是放置,也就是向服务器新添加数据,就是所谓的增。
  • DELETE:从字面意思也能看出,这种方式就是删除服务器数据的过程。

GET 和 POST 的区别

  1. Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。 但是这种做法也不时绝对的,大部分人的做法也是按照上面的说法来的,但是也可以在get请求加上 request body,给 post请求带上 URL 参数。
  2. Get请求提交的url中的数据 多只能是2048字节,这个限制是浏览器或者服务器给添加的,http协议并没有对url长度进行限制,目的是为了保证服务器和浏览器能够正常运行,防止有人恶意发送请求。Post请求则没有大小限制。
  3. Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
  4. Get执行效率却比Post方法好。Get是form提交的默认方法。
  5. GET产生一个TCP数据包;POST产生两个TCP数据包。对于GET方式的请求,浏览器会把http header和data一并发送出去,服务器响应200(返回数据);而对于POST,浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)。

首先是查找浏览器缓存,浏览器会保存一段时间你之前访问过的一些网址的DNS信息,不同浏览器保存的时常不等。 如果没有找到对应的记录,这个时候浏览器会尝试调用系统缓存来继续查找这个网址的对应DNS信息。 如果还是没找到对应的IP,那么接着会发送一个请求到路由器上,然后路由器在自己的路由器缓存上查找记录,路由器一般也存有DNS信息。 如果还是没有,这个请求就会被发送到ISP(注:Internet Service Provider,互联网服务提供商,就是那些拉网线到你家里的运营商,中国电信中国移动什么的),ISP也会有相 应的ISP DNS服务器,一听中国电信就知道这个DNS服务器的规模肯定不会小,所以基本上都能在这里找得到。题外话:会跑到这里进行查询是因为你没有改动过"网络中 心"的"ipv4"的DNS地址,万恶的电信联通可以改动了这个DNS服务器,换句话说他们可以让你的浏览器跳转到他们设定的页面上,这也就是人尽皆知的DNS和HTTP劫持,ISP们 还美名曰“免费推送服务”。强烈鄙视这种霸王行为。我们也可以自行修改DNS服务器来防止DNS被ISP污染。 如果还是没有的话, 你的ISP的DNS服务器会将请求发向根域名服务器进行搜索。根域名服务器就是面向全球的顶级DNS服务器,共有13台逻辑上的服务器,从A到M命名,真正 的实体服务器则有几百台,分布于全球各大洲。所以这些服务器有真正完整的DNS数据库。如果到了这里还是找不到域名的对应信息,那只能说明一个问题:这个域名本来就不 存在,它没有在网上正式注册过。或者卖域名的把它回收掉了(通常是因为欠费)。 这也就是为什么打开一个新页面会有点慢,因为本地没什么缓存,要这样递归地查询下去。 多说一句,例如"mp3.baidu.com",域名先是解析出这是个.com的域名,然后跑到管理.com域名的服务器上进行进一步查询,然后是.baidu,最后是mp3, 所以域名结构为:三级域名.二级域名.一级域名。 浏览器终于得到了IP以后,浏览器接着给这个IP的服务器发送了一个http请求,方式为get,例如访问nbut.cn

这个get请求包含了主机(host)、用户代理(User-Agent),用户代理就是自己的浏览器,它是你的"代理人",Connection(连接属性)中的keep-alive表示浏览器告诉对方服务 器在传输完现在请求的内容后不要断开连接,不断开的话下次继续连接速度就很快了。其他的顾名思义就行了。还有一个重点是Cookies,Cookies保存了用户的登陆信息,在每 次向服务器发送请求的时候会重复发送给服务器。Corome上的F12与Firefox上的firebug(快捷键shift+F5)均可查看这些信息。 发送完请求接下来就是等待回应了 当然了,服务器收到浏览器的请求以后(其实是WEB服务器接收到了这个请求,WEB服务器有iis、apache等),它会解析这个请求(读请求头),然后生成一个响应头和具体响 应内容。接着服务器会传回来一个响应头和一个响应,响应头告诉了浏览器一些必要的信息,例如重要的Status Code,2开头如200表示一切正常,3开头表示重定向,4开头, 如404,呵呵。响应就是具体的页面编码,就是那个……,浏览器先读了关于这个响应的说明书(响应头),然后开始解析这个响应并在页面上显示出来。在下一次CF的时候(不 是穿越火线,是http://codeforces.com/),由于经常难以承受几千人的同时访问,所以CF页面经常会出现崩溃页面,到时候可以点开火狐的firebug或是Chrome的F12看看状 态,不过这时候一般都急着看题和提交代码,似乎根本就没心情理会这个状态吧-.-。 如果是个静态页面,那么基本上到这一步就没了,但是如今的网站几乎没有静态的了吧,基本全是动态的。所以这时候事情还没完,根据我们的经验,浏览器打开一个网址的时 候会慢慢加载这个页面,一部分一部分的显示,直到完全显示,最后标签栏上的圈圈就不转了。

这是因为,主页(index)页面框架传送过来以后,浏览器还要继续向服务器发送请求,请求的内容是主页里面包含的一些资源,如图片,视频,css样式等等。这些"非静态"的 东西要一点点地请求过来,所以标签栏转啊转,内容刷啊刷,最后全部请求并加载好了就终于好了。

需要说明的是,对于静态的页面内容,浏览器通常会进行缓存,而对于动态的内容,浏览器通常不会进行缓存。缓存的内容通常也不会保存很久,因为难保网站不会被改动。

首先根据目的 IP 和路由表决定走哪个网卡,再根据网卡的子网掩码地址判断目的 IP 是否在子网内。如果不在则会通过 ARP 缓存查询 IP 的网卡地址,不存在的话会通过广播询问目的 IP 的 MAC 地址,得到后就开始发包了,同时 MAC 地址也会被 ARP 缓存起来。