面试之计算机网络

计算机网络体系结构

  • OSI体系从下至上依次为:物理层、数据链路层、网络层、传输层、会话层、表示层、应用层。

  • 综合体系从下至上依次为:物理层、数据链路层、网络层、传输层、应用层。

  • TCP/IP体系从下至上依次为:网络接口层、网络层、传输层、应用层。

一般来说,网卡中封装了物理层和数据链路层的协议与工作。各层的作用为:

物理层,定义物理设备标准,将数字信号转化为物理信号传输,如光、电磁波等。

数据链路层,格式化数据为帧,提供基本的错误检测。数据链路层提供的是相邻两点之间的点到点的服务,即主机与路由器、路由器与路由器间的通信。

网络层,为不同的主机提供通信服务(故需要源ip与目标ip),常见协议有IP、ICMP(基于IP协议,用于发送控制信息,例如超时、主机或端口不可达、路由不可用等)、ARP(将ip地址映射为mac地址,属于广播发送与单播回应)等。网络层提供的是端到端的服务,即主机与主机间的通信,但它不保证消息的有序性和可靠性,故需要上层协议来保证,例如TCP。

传输层,为不同的主机提供进程间通信服务(故还需要源端口与目标端口),常见协议有TCP、UDP。

应用层,直接为用户进程提供服务,常见协议有HTTP、FTP、SMTP、DNS等。

 

TCP与UDP的区别

  • TCP面向连接,UDP面向无连接。

  • TCP基于字节流,UDP基于数据报。

  • TCP是可靠的,通过seq和ack保证数据不丢失和有序,提供超时重传、错误校验、流量控制和拥塞控制,UDP是不可靠的。

 

交换机与路由器

交换机

交换机工作在数据链路层,用于实现网段内通信,维护的是mac地址表,表项为<端口号mac地址>,根据接收到的数据帧(同时将接收端口与源mac地址端存在mac地址表中)的目标mac地址在指定端口进行转发。当目标mac地址不存在于表中时,将数据帧从除了接收该帧的端口之外的端口泛洪出去。交换机每次接收到数据帧后需要做一个两层的解封装从而得到目标mac地址。

路由器

路由器工作在网络层,用于实现跨网段通信,维护的是路由表,表项为<目的网段(ip + 掩码),路由来源下一跳出接口>,根据接收到的数据包的目标ip地址与路由表的每一项进行路由匹配,然后在指定出接口进行转发。如果没有匹配的条目则直接丢弃(如果有默认路由则从默认路由转发)。路由来源分三种:

  • 直连路由,直接连接在路由器上的网段,由路由器自动发现并生成。

  • 静态路由,由网络管理员手工添加。

  • 动态路由,路由器之间相互学习生成。

路由器每次接收到数据包后需要做一个三层的解封装从而得到目标ip地址。路由器的功能分为两个平面:

  • 控制平面,负责计算路由表。

  • 数据平面,根据路由表决定转发到哪个接口。

 

DHCP协议

运行在局域网中的应用层协议(基于UDP),用于动态分配IP地址。DHCP的响应包括随机分配的IP地址,子网掩码,DNS服务器地址,默认网关(第一跳路由器)。一般的无线宽带路由器都可以运行DHCP协议。

 

TCP协议

传输层协议,特点是面向连接、可靠、基于字节流。

三次握手

  1. Client发送SYN到Server;(TCP/IP协议规定SYN会消耗一个序列号)

  2. Server回复SYNACK

  3. Client回复ACK;(第三步可以携带消息)

为什么是三次?握手的目的是为了双方确定各自的发送序列起始号,以及其他控制信息(如接收窗口大小),发送序列号之后还需要确认,故需要三次握手。

完成二次握手后服务器会将此连接放入半连接队列,等待三次握手结束,三次握手后的连接放入全连接队列。当半连接队列中的连接等待客户端的确认超时后,会进行重传,一般是1s、2s、4s......直到达到阈值后将其从半连接队列中丢弃。

四次挥手

  1. Client发送FIN

  2. Server回复ACK

  3. Server发送FIN

  4. Client回复ACK

为什么是四次?因为TCP/IP是全双工的,允许同一时刻数据的两个方向的传输(半双工指同一时刻只能有一个方向但可以切换)。两次挥手只能确定一方不再发送消息,另一方不再接收消息,故还需要两次挥手(两次挥手后已经释放了一半连接)。但第二次和第三次挥手是可以合并的,当服务器收到客户端的fin请求后可以将ACK和自己的FIN请求一起发给客户端(延迟ACK)。

客户端发送最后一个ACK后进入TIME_WAIT状态,等待2MSL(任意报文在网络中的最长存活时间)后才会真正关闭连接,为什么?1. 保证客户端的最后一个ACK能成功到达服务器,如果客户端在TIME_WAIT期间再次收到了服务端的FIN报文,说明客户端上次发送的ACK丢失了,则重新发送最后一个ACK;2. 保证网络中不会出现这个即将断开的连接的请求报文(如果不等待,网络中滞留的该旧连接的报文就可能在建立新连接后到达服务器)。

为什么是两个MSL?客户端等待时间要大于服务器的FIN报文传输时间+超时重传时间(一定是小于MSL的),故保守起见取2MSL。

SYN攻击

全称SYN洪泛攻击。客户端在短时间内伪造大量不存在的IP地址,不断向服务器发送SYN请求,它们会一直占用服务器的半连接队列,且服务器会不断尝试回复ACK确认直到时间超出阈值,这会导致正常的SYN请求因队列满而被抛弃。SYN攻击是一种典型的拒绝服务攻击(Denial of Service,DoS)。

如何防止SYN攻击?当检测到服务器出现大量的半连接,且这些连接的源IP是随机的时候,基本可以确定是SYN攻击,从而加以防范,如降低SYN timeout从而快速丢弃SYN请求。

滑动窗口

滑动窗口是为了增加双方收发消息的效率而出现,发送方和接收方都有这样一个窗口,窗口的大小均可以设置。发送方的窗口包含已发送但还未收到确认的帧以及还可以发送的帧,发送窗口的大小表示一次性最多能发送多少个还未确认的帧

  • 当发送方和接收方的窗口大小都为1时,称为“停止等待协议”,即发送方每发送一帧都需要等待接收方确认后才能继续发。

  • 当发送方窗口>1且接收方窗口=1时,称为“后退N帧协议”,接收方只能按序接收,当发送方发现丢包时,需要重发该帧及之后发的所有帧。后退N帧协议可以采用延迟确认,即等待收到一定的连续帧后再发送一个最后收到的帧的确认帧,具有累计确认效应。

  • 当发送方和接收方的窗口大小都>1时,称为“选择重传协议”,接收方可以乱序接收,需维护一个缓冲区且对每一帧都进行确认,只有当序号最小的帧确认后窗口才能右移。当发送方某一帧超时后只需重发该帧,故不具有累计确认效应。

注:丢包 = 一次超时or三个重复确认(接收方发现数据并不是期望的序号,于是发送三个相同的ack表示重传,从而实现快速重传丢包数据,不用让发送方等待超时后在重传)

流量控制

流量控制是针对发送方和接收方而言,操作的是滑动窗口,影响的只是发送方。目的是防止发送方发的太快,耗尽接收方的资源,从而使接收方来不及处理。主要通过接收方给发送方返回一个最大窗口大小(依据是接收方的剩余缓冲区大小),发送方接收到后会调小自己的发送窗口从而实现抑制发送。当最大窗口大小为0时发送方不再发送,但会周期性给接收方发送窗口探测数据段,从而恢复发送。

拥塞控制

拥塞控制是针对整个网络状况而言,操作的是拥塞窗口,影响的是整个网络。当网络状况有限时,防止发送方发送太快使得网络来不及处理,从而导致网络拥塞。实现机制是慢启动+拥塞避免。设拥塞窗口大小为n(初值为1):

  • 慢启动。当发送方确认了现在的n帧后,将拥塞窗口大小*2,直到达到阈值后变为拥塞避免。

  • 拥塞避免。当发送方收到一个确认帧后,将拥塞窗口+1(单位是最大报文长度MSS),直到发现丢包。发生丢包后会将阈值变为当前窗口大小/2,并重新回到慢启动阶段。

一句话:流量控制是为了避免数据接收方忙不过来,拥塞控制是为了避免路由器和交换机等网络核心设备忙不过来。

长连接与短连接

  • 短连接指双方建立连接后只进行一次网络传输后就断开连接,优势是不用管理太多连接,劣势是多次握手和挥手导致开销大。

  • 长连接指双方建立连接后进行多次传输后断开连接,优势是连接复用效率更高,劣势是需要采取额外措施确保连接可用。主要有如下两种方式:1. 利用TCP自带的保活机制(Keepalive)实现,保活机制会定时发送探测报文来识别对方是否可达,默认定时间隔是两小时,可以根据需要在操作系统级别修改。2. 上层应用主动的定时发送”心跳包“,探测是否能成功送达到另外一端。 一旦检测到连接不可用,服务器就断开连接以缓解压力。如Netty提供的空闲事件检测机制。

 

TCP长连接建立后长时间没有通讯会自动断开吗?

当连接双方都正常运行时,连接将永远不会断开。Keepalive机制涉及到的三个参数:

  • tcp_keepalive_time,最后一次正常通讯到发送第一个保活探测包的时间间隔,默认2小时。

  • tcp_keepalive_probes,发送保活探测包后没有收到ACK时的重发次数上限。

  • tcp_keepalive_intvl,发送保活探测包后没有收到ACK时的重发间隔。

当TCP连接通过Keepalive机制发送保活探测包后,如果收到了ACK则重置保活定时器时间(即两小时后仍无通讯再触发),如果另一端宕机或网络异常,此时收不到对方的ACK,则每间隔tcp_keepalive_intvl发送一次保活探测包,如果发送了tcp_keepalive_probes次后仍收不到对方的ACK则关闭连接并向对方发送RST包通知对方关闭连接。

 

Http协议

应用层协议,是一种无状态的协议(即不保存之前的请求或响应的任何信息,所以有Cookie和Session存在),采用请求/响应模型,一般由客户端发起,服务器响应,默认端口为80。目前有1.0,1.1,2.0三个版本,1.1解决了1.0连接复用问题,2.0解决了1.1并发请求困难的问题。其中2.0采用二进制传输数据,1.0和1.1都采用文本格式。

请求和响应

  • 请求包含请求行、请求头、请求体。请求行包括请求方法、URI(与IP和端口结合起来变为URL)、Http协议版本。请求头包含一些KV键值对,告诉服务器一些自身信息,比如当前URL、浏览器可以解析的内容类型、部分浏览器和操作系统信息、期望收到的响应体编码、Cookie等。请求体用于传输额外的自定义信息。

  • 响应包含响应行、响应头、响应体。响应行包括Http协议版本、状态码、状态码简要描述。响应头包括响应体类型(Content-Type,如text/html、applicaiton/json)、响应体编码(Content-Encoding,如gzip)、日期、响应体大小等。响应体就是我们想要的资源文件和数据。

注:响应主体 = 内容编码(内容类型(数据))

请求方法

请求方法共有GET、POST、PUT、DELETE等共八种,用于对资源进行不同操作的标识,最常用的是GET和POST,随着Restful风格的流行,其他请求方法也逐渐开始使用。GET和POST的区别如下:

  • GET请求没有请求体,请求参数会附加到URL后面,以KV键值对的形式用?和&连接,故会暴露参数,且由于URL长度受限,GET附加参数大小也受限。

  • POST请求有请求体,请求参数会放在请求体中,与请求头中类似以KV键值对的形式存放,参数不会暴露在URL中。

常见状态码

  • 200,正常。

  • 303,资源重定向。

  • 404,找不到资源。

  • 500,服务器内部错误。

Keep-Alive

TCP的Keepalive是为了确保长连接是否有效可用,Http的Keep-Alive是为了标识短时间内该连接是否可以复用(多次发送请求)。Http1.0版本默认是关闭的,Http1.1版本默认是开启的,现在一般的浏览器都使用Http1.1。

浏览器输入URL回车后的步骤

  1. 查询本机是否有该域名的缓存,若没有则去DNS服务器上查询并缓存。

  2. 根据1中得到IP和PORT,去访问服务器建立TCP/IP连接。

  3. 发送Http请求获取资源。

  4. 服务器响应Http请求。

  5. 浏览器解析html资源,并进一步请求html中包含的其他资源(css、js、图片)。

  6. 断开连接。

  7. 浏览器渲染页面并展示。

 

Https协议

Https是身披SSL外壳的Http,SSL是位于传输层和应用层之间的一层安全防护层,用于实现安全通信。

数字证书内容

申请人身份信息、公钥、证书过期时间、CA的信息、生成摘要采用的hash算法、生成签名采用的非对称加密算法、上述所有信息的签名。对明文hash后得到摘要,对摘要进行非对称加密后得到签名。

握手流程

  1. Client生成(random1+自己支持的加密算法和协议)发送给Server。

  2. Server生成(random2+自己的证书+确定的加密算法和协议)发送给Client。

  3. Client验证Server证书,生成random3,用random123生成对称密钥和HMAC盐值,并用Server的数字证书中的公钥加密(random3)发送给Server。HMAC算法原理:hash(sault, msg),采用的hash算法、盐值sault、明文msg均为外部输入。

  4. Server用自己的私钥解密得到random3,用random123生成对称密钥和盐值,告知Client安全通道建立完毕。

注:括号内是传输的内容。random3不是简单的随机数,还包含了确定的加密算法与协议等信息,具体称为pre-master secret 。Server可以用它在第3步验证消息是否被修改,比如攻击者篡改协商好的加密算法和协议等。加密后的通信内容为(明文拼接盐值后的签名,明文与签名经对称加密后的密文)。

证书验证过程

Client首先查看CA资格是否合法,不通过则浏览器提示该网站不受信任。用证书中的公钥解密得到签名(用证书中的非对称加密算法),用证书中的算法再次计算证书内容的签名以验证证书是否被篡改,验证通过则认为该Server可信且获得其公钥。

 

Http缓存

为了减少建立TCP连接以及网络传输的开销,服务器可以设置响应头来告知浏览器是否可以缓存、缓存时间、是否强校验等,主要针如css、js、图片等更新频率不大的静态文件。响应头字段Cache-Control可以设置的值有(不是全部):

  • max-age,指定缓存有效时间(Http1.1独有),Expire头也可设置过期时间(1.0就有了,1.1中优先级低于max-age),这种方式属于走强制缓存。

  • public,表明响应可以被客户端和代理服务器等缓存。

  • private,表明响应只能被客户端缓存。

  • no-cache,强制浏览器在使用缓存前向服务器验证缓存是否过期,这种方式属于走协商缓存。

  • no-store,禁止缓存,每次请求都要向服务器重新获取数据。

强制缓存与协商缓存

  • 强制缓存,在缓存未过期之前,直接在缓存中取,强制缓存生效时状态码为200。缺点:在缓存过期时间内,浏览器无法主动感知到服务器资源的变化。解决方法:在项目发布时修改可能被缓存的文件的文件名......

  • 协商缓存,无论缓存是否过期,每次使用缓存时都需要向服务器发请求验证缓存是否过期,协商缓存生效时状态码为304。

如何验证缓存过期

  • 请求头if-Modified-Since + 响应头Last-Modified,通过比对服务器与浏览器缓存的最近修改时间判断是否过期,这种方式的精确度为秒级,不够精确,故出现新的响应头Etag。

  • 请求头if-None-Match + 响应头Etag,通过比对服务器与浏览器缓存的唯一内容标识(文件指纹,即数字摘要)判断是否一致。这种方式的优先级更高,毕竟更精确。

注:不想使用缓存可使用ctrl+f5强制刷新。

 

DNS原理

平时看到的每个域名后面都有隐藏的“.root”根域名,如“www.baidu.com”实质是“www.baidu.com.root”。从左至右依次为:主机名.次级域名.顶级域名.根域名,其中次级域名由用户自己申请,主机名是用户在自己的域中为服务器分配的名字。每一级域名都有自己的服务器,DNS解析时从根域名服务器(根域名服务器的ip一般是固定的保存在配置文件中)开始分级查询,每次向当前级的多个域名服务器发送请求,保留最快的响应作为缓存并找到下一级域名对应服务器的ip地址,域名服务器在响应时可以设置TTL(time to live)值让客户端在TTL时间内不再发起DNS请求。域名服务器的响应分不同类型,主要有:

  • NS,保存下一级域名信息的服务器的域名。

  • A,保存下一级域名信息的服务器的ip地址。

  • MX,邮件记录,接收电子邮件的服务器地址。

  • CNAME,返回另一个域名,即当前查询的域名是另一个域名的跳转(别名)。如www.baidu.com有别名www.a.shifen.com,使用CNAME的好处:当服务器ip地址变化时无需变动面向客户的www.baidu.com域名,还可用于CDN加速。

  • PTR,逆向查询记录,用于从ip地址查询域名。

为什么用UDP?

因为DNS查询只需要一次请求一次响应,用TCP还需握手挥手消耗较大,而且DNS请求与响应的数据量都比较小,满足UDP一个数据报的最大大小512字节(如果超过512字节则DNS改用TCP传输)。

递归查询和迭代查询

DNS解析主要有两大步骤:1. 主机向本地域名服务器发起DNS查询;2. 本地域名服务器先向根域名服务器查,然后向顶级域名服务器查,最后向次级域名服务器(权限服务器)查到域名对应的ip地址。

负载均衡

  • 一个域名在同一时刻只能对应一个ip地址,但可以在域名服务商那里设置一个域名对应多个ip地址,从而让访问同一个域名的请求分散到多个实际的服务器。此时为了避免单点故障,还可以挑出主服务器负责读写,从服务器拷贝主服务器数据负责读。

  • 一个ip可以有多个域名,这个没有限制。

CDN加速

CDN即内容分发网络(Content Delivery Network),主要原理是将源站的资源缓存到位于各个地方的CDN节点上,用户请求资源时,会就近返回节点上缓存的资源,从而缓解源站压力,保证用户访问资源的速度和体验。当需要使用运营商提供的CDN服务时,运营商会给我们一个域名,此时需要设置我们自己网站的域名的CNAME指向运营商提供的域名(需要找自己网站的域名解析服务商进行修改)。使用CDN服务后,当用户访问我们的网站发起DNS解析请求时会得到一个CNAME(即运营商提供的域名),从而进一步访问运营商提供的智能DNS解析服务器(CDN的核心),DNS解析服务器会返回其节点群中用户访问速度最快的CDN结点的ip,最后用户找该CDN结点拿数据,若此时该CDN结点没有对应数据则会向源站发起请求然后缓存结果供以后用户访问(这个过程称为回源)。

 

跨域

浏览器的同源策略

出于安全考虑,浏览器禁止一个网页内的脚本(即js代码)请求非同源网站的cookie、storage、dom以及发出ajax请求,判断是否同源的依据的协议、ip地址、端口号,三者任一不同则称为跨域。但同源策略并不限制表单请求、a标签的href属性、script标签的src属性等请求跨域资源。

JSONP解决方案

利用了同源策略不限制script标签的src属性的特点,将请求封装在src中,即在url后面拼接参数,例src='http://test.com/data?callback=func',这里的callback即回调函数,此时需要服务器端配合,不再返回单纯的JSON数据,而是调用前端的准备好的回调函数,将真正的数据作为参数传入回调函数即可,例callback({"name":"zhangsan",age:24})。JSONP的缺点是只能解决get请求,而且需要前后端一起配合。

CROS解决方案

推荐使用方案,本质是由服务端在响应请求时添加一些特殊的响应头,最主要的是'Access-Control-Allow-Origin'响应头,告知浏览器允许这次跨域请求,还有其他响应头可以控制浏览器请求方式、是否允许携带cookie等。另外,浏览器在发起跨域请求时会判断这次请求是否是’简单‘的ajax请求(判断依据是请求方式是否是基本的GET、POST等,以及请求头是否是最基本的字段)。如果是简单的ajax请求则发送一次请求即可,否则需要发起两次请求:第一次请求询问服务器是否允许自身的跨域请求,第二次才是真正的ajax请求。

 

TCP粘包拆包问题

  • TCP存在一个优化算法Nagle,当发送方发送的数据体积很小时,会先将其先放在缓冲区,当缓冲区大小接近MTU(最大发送单元)或者达到间隔时间阈值时再一起发出去,这称为粘包问题。

  • 当发送方发送的数据体积超过MTU时,会将其切割为多个包发送,这称为拆包问题。

解决办法一般有:

  • 添加特殊标识符标识结束,如\r\n,FTP协议使用的方法。

  • 自定义协议,添加长度字段。

Traceroute

traceroute命令用于追踪数据包在网络上传输的路径,显示了到达目标主机前的每一跳的IP地址和延迟时间。其原理是源主机先发送3个TTL为1的IP数据包给目的主机,当处理该数据包的第一个路由器接收到之后会将TTL减1,然后发现TTL等于0即过期,则给源主机发送一个ICMP报文提示“超时”,同时携带了该路由器的地址。然后继续发送3个TTL为2的IP数据包给目的主机......。重复这个过程直到数据包到达目标主机,通过设置目标端口为不可能的值,让目标主机返回“端口不可达”的ICMP报文,从而区分是路由器还是目标主机。traceroute发送的是UDP数据包。

路由器转发报文的时间包括:

  • 处理延时。指路由器对接收到的报文进行错误校验,提取目标IP并查询路由表等操作的延时。

  • 排队延时。当路由器转发数据报的速度小于接收的速度时,则会将数据报放入缓冲区排队,若队列满则直接丢弃。

  • 传输延时。指路由器A将一个数据报的所有比特打出去的时间。

  • 传播延时。指每个比特从路由器A传播到下一跳到的时间。

posted @   万里阳光号船长  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
点击右上角即可分享
微信分享提示