Skip to content

整理面试题 - 2024-10-18 - 开始

深入解释tcp/ip协议

  • 分段一: 交换机的出现
    • 最开始的时候,两台计算机通信,只要用一根网线将他们连接起来就可以了,如果是老式的设备,可能还需要调整一下网线的线序
    • 但是随着计算机的增多,这种连接方式已经不能满足需求了,而且成本也太高了,操作也麻烦,于是那时候可以把每个计算机的网线拧在一起,这样可以实现多台计算机之间相互通信,而拧在一起的这个线团,就是最早期的集线器
    • 但集线器的缺点也很明显,每次发送的消息都会发给所有人,另外如果多台计算机同时发送消息会造成干扰,导致数据紊乱,于是交换机就出现了
    • 交换机通过内部的mac地址表,来决定信息流向,接入交换机的设备都必须要有自己的mac地址,计算机的mac地址是设备出厂时就设定好了的,这是全球唯一的,可以理解为设备的UUID
  • 分段二: 交换机的工作方式
    • 如果A计算机要发送消息给B计算机,它需要在报文里写上自己的mac地址和B计算机的mac地址,将他们一起发送给交换机,交换机会将A计算机的mac地址记下来,跟接口1绑定(假定A计算机连接的是交换机的接口1),但此时交换机不知道B计算机mac地址对应哪个接口,于是会把消息以及目标即B计算机的mac地址发送给所有人,这个做法叫做泛洪
    • 当连接交换机的其他计算机C、D、E......等计算机接收到消息后,发现目标mac地址和自己不匹配,于是就会丢弃这个消息
    • 而B计算机接收到消息后,发现自己的mac地址可以匹配上,于是发送消息回应,同样的,回应的消息也需要写上自己的mac地址和A计算机的mac地址,回应的消息经过交换机之后,交换机也会将B计算机的mac地址和接口2进行绑定(假定B计算机连接的是交换机的接口2),由于之前交换机已经将A计算机的mac地址和接口1进行了绑定,所以交换机知道A计算机的mac地址应该发送给哪个接口,于是不需要再次泛洪,而是会将消息直接投递到接口1,从而直接把消息发送给A计算机,这样就完成了交换机mac地址发现到通信的过程
    • 如果以后A计算机还要发送消息到B计算机,交换机就会直接将消息发送到接口2,而不需要再次泛洪,这就是交换机的原理,,然而mac地址是根据设备绑定的,如果设备更换了网卡,那么mac地址就会发生变化,之前沟通过的计算机就会无法通信,需要再次泛洪,即目标计算机也要跟着修改A计算机的mac地址,所以mac地址的通信方式,对于更换网卡的情况,不是很友好,这时候我们需要一个更抽象的地址,这个地址就是ip地址
  • 分段三: ip地址的工作方式
    • 假如依旧是A计算机发消息给B计算机,但是这次不是mac地址了,而是ip地址传输数据
    • A计算机需要在报文上写好自己的ip地址和B计算机的ip地址,因为要经过交换机,所以mac地址也要加上,但A计算机此时并不知道B计算机的mac地址,于是目标的mac地址就写不知道,然后将他们一起发送给交换机,然后根据交换机的泛洪,把消息发送给所有人,并比对所有计算机的ip地址,如果ip地址不匹配,就会将消息丢弃,直到匹配到B计算机的IP地址,B计算机收到消息后,会将A计算机的IP地址和mac地址绑定起来,以备下次使用,随后会对A计算机进行回应,告诉A计算机自己的mac地址,A计算机接收到回应后,会将B计算机的ip地址和mac地址绑定起来,以备下次使用,有了mac地址,两台计算机就可以直接进行通信了
    • 这个由IP地址到获得mac地址的过程,就是ARP协议,而计算机里面mac地址跟IP地址绑定的数据表则是APRP记录表
  • 分段四: 多网络的通信 - 子网掩码的由来
    • 由于交换机泛洪特性,我们可以透过交换机直接将不同的网络联合起来,但是网络规模庞大之后,这样的联网方式并不合理,由于交换机会把每个经过的mac地址都保存起来,如果联网设备数量巨大,那么交换机的mac地址表将会无法容纳,另外交换机的全网泛洪也会导致效率问题(网络拥堵),于是我们希望将网络隔离开来,将网络分成不同的网段,交换机只用来传输同一网段的消息,于是有了子网掩码的概念
    • 子网掩码简单理解就是告诉计算机,子网的ID是IP的前面多少位数,简单理解,子网掩码前三段有值,那么子网IP就是IP的前三段,举例说明:
      • 子网掩码: 255.255.255.0 => 前三段有值
      • ip地址: 192.168.1.5 => 子网ID: 192.168.1.0
      • ip地址: 192.168.2.5 => 子网ID: 192.168.2.0
    • 这样我们就可以通过比对IP和子网ID,来确定是否属于同一个子网(网段),从而决定是否需要通过交换机进行通信,但这只是粗泛的理解,实际上子网掩码的规则要复杂的多,实际计算需要将IP和子网掩码转换成二进制进行计算,这样颗粒度更高,但原理是一样的,同样是按照子网掩码确定截取IP前多少位来作为子网ID,这里就不展开了
    • 这样计算机就可以知道目的IP是属于当前网段还是外网,如果是当前网段,则直接通过交换机通信,如果发送消息到外网,将交给专门的设备帮忙转发,这个设备就是路由器
  • 分段五: 路由器的工作方式
    • 如果计算机A要发送消息给计算机C,并且通过子网掩码计算得知计算机C的IP地址不在当前子网,即当前IP为外网,那么就会将消息发送给路由器
    • 而计算机A之所以知道是哪台服务器,是因为计算器A的网关配置的是路由器的IP地址
    • 网关顾名思义就是各个子网的关口、出口,非内网的消息都经过网关出去
    • 路由器接受到消息后,怎么知道下一步要将消息给谁呢,是因为路由表,路由表可以配置网段和下一跳,它们用来决定各网段的消息下一步应该交给哪一个路由器设备,于是路由器就通过这种接力的方式将消息发送给目标计算机C
    • 路由表是手动配置的,当路由设备多起来之后,靠人工维护不太现实,于是有了自动互助学习、自动管理路由表的RIP、OSPF等动态路由协议
    • 当网络规模继续扩大之后,OSPF等协议也显得力不从心,于是有了BGP等协议,BGP协议是一种更高级的动态路由协议,可以自动管理路由表,并且可以自动更新路由表,但原理都是一样的,就是通过路由表来决定消息的下一步走向
    • 交换机、路由器各协议及IP协议的作用下,使用者可以不用关系复杂的网络环境,计算机通信就像单根网线直连一样,只需要关注自己的网络环境,通过配置网关,就可以实现跨网络通信,而不用关心消息的传输过程,但此时还有问题,例如IP协议只负责发消息投递到计算机,但我们的计算机是多应用的,比如浏览器、微信、QQ等,那么消息应该交给哪个应用呢,这就需要端口的概念了
  • 分段六: 端口 - UDP协议
    • 不同的应用,我们使用不同的端口,发送报文时,除了前面的mac地址、IP地址外,还要加上源端口和目的端口,这样计算机接收到消息后,就可以根据端口来决定将消息交给哪个应用,从而实现多应用同时通信,而不用担心消息混乱的问题
    • 这种带端口的消息发送方式,其实就是UDP协议
    • UDP简单粗暴,但还是存在很多问题,例如消息丢失、消息重复、消息顺序混乱等,所以我们需要设计一个稳定可靠的协议,于是TCP协议就出现了
  • 分段七: TCP协议 => 传输控制协议
    • 首先,网络是不稳定的,我们发送的消息很有可以能会在途中丢失,所以需要设置重试机制,当消息发送失败之后重新发送(假设为计算机A),为了判断是否发送成功,还需要在接收方(假设为计算机C)接收到消息之后,必须发送确认消息给发送方(计算机A),这样计算机A就知道消息已经成功发送,如果计算机A在规定时间内没有收到确认消息,那么就会重新发送,这就是TCP协议的可靠传输机制,这就保证了消息必达
    • 如果有大段的内容发送给计算机C,那么计算机C可能无法一次性接收完,很容易造成部分丢失,导致全部内容都要重新发送,于是TCP协议设计了分段机制,我们将数据分成多个包进行发送,如果分包发送失败,我们只需要重传分包数据即可,提高了传输效率
    • 此外,TCP协议还将每个包配上序号,这样计算机C就可以根据序号来重新组合消息,从而保证消息的顺序,这就是TCP协议的有序传输机制,并且接收方(计算机C)接收到消息,回复确认,也要带上序号,这样发送方(计算机A)就可以知道哪些消息已经成功发送,哪些消息需要重传
    • 注意:我们在前面的理解里,分包是一次性全部传过去的,但现实中,由于网络,客户端计算机处理能力等一系列原因,导致溢出的数据传输失败,于是需要控制每次传输分包的个数,于是有了滑动窗口,拥塞控制等技术,目的都是动态调整分包个数来优化传输流程,
    • 总结: 在TCP中,数据传输过程中会遇到两个主要的问题:丢包和延迟。为了解决这两个问题,TCP引入了慢启动和快重传机制
    • 不管是发送方的重传机制,还是接收方应答,数据整理机制,都需要双方分配计算资源来处理,为了提高计算效率,需要双方约定好一起开启,一起结束,而这个约定的开启和结束就叫做连接的建立和关闭,其实就是三次握手和四次挥手
  • 分段八: TCP连接的建立和关闭
    • 建立连接: 三次握手
      • 发送方(计算机A)先传达一个连接意愿 => 在吗,来一把?
      • 接收方(计算机C)收到连接意愿后,回复一个连接确认,表示同意连接 => 在,来吗
      • 发送方(计算机A)收到连接确认后,再次发送一个连接确认,表示连接成功 => 来了,来了
    • 关闭连接: 四次挥手
      • 发送方(计算机A)先传达一个关闭意愿 => 要不退了吧
      • 接收方(计算机C)收到关闭意愿后,回复一个关闭确认,表示同意关闭 => 行,等我这把刷完
      • 接收方(计算机C)数据处理完毕,再向计算机A传达一个关闭意愿 => 刷完了,你可以退了
      • 发送方(计算机A)收到关闭确认后,再次发送一个关闭确认,表示关闭成功 => 你也退吧,下次别再打野了
  • 分段九: NAT协议
    • UDP协议和TCP协议是应用层协议的根基,它们为应用层协议提供了传输保障,使得应用层协议可以专注于业务逻辑的实现,而不必担心消息的传输问题,所有的应用层协议都是在他们的基础上建立的
    • 随着网络的发展壮大,IP地址慢慢不够用了,于是有人想出了子网共用一个IP地址的方法
    • 假如计算机A和计算机B,同时发送消息给计算机C,但是它们没有公网IP,于是交给了网关路由器转发,路由器接收到后,建立端口映射表,记录着源端口、新端口,以及对应的内网IP,之后把报文中的来源IP改成公网IP,端口改成新端口,冒充子网计算机与外部通信,为计算机C响应消息时,网关路由器就可以根据端口映射表,把消息转发给对应的内网计算机(计算机A或计算机B),这就是NAT协议,NAT协议有效地解决了IP地址和IP地址匮乏问题
    • 这里加个补充,IP地址慢慢不够用了之后,又引入了IPv6协议,IPv6协议可以提供更多的IP地址,但是IPv6协议并不是直接替代IPv4协议,而是和IPv4协议共存,所以我们需要一个协议来将IPv4协议和IPv6协议进行转换,于是有了NAT协议,它可以将IPv4协议和IPv6协议进行转换,使得IPv4协议和IPv6协议可以互相通信
    • 总结: 将一个IP地址分成多个子网,每个子网使用不同的子网掩码,这样就可以实现多个子网共用一个IP地址,这就是NAT协议,它可以将多个子网共用一个IP地址,从而实现IP地址的复用

get和post的区别

  • get和post都是http的请求方法,本质上都是tcp连接,并无区别;但是由于http的规定及浏览器和服务器的限制,导致他们在应用过程中会有所不同
  • get
    • get主要用于获取信息(查询)
    • get的请求数据放在url中,因url有长度限制(这个长度限制主要是由浏览器和 Web 服务器所决定的)),所以传输的数据有大小限制
    • GET 方法只产生一个 TCP 数据包,浏览器会把 请求头+请求数据一起发送过去,服务器响应200ok(返回数据)
    • get是可以被浏览器缓存的;所以如果下次传输的数据相同,那么可能会返回缓存中的内容,以求更快的展示
  • post
    • post主要于提交数据,即POST请求可能会导致新的资源的建立和/或已有资源的修改
    • post的数据放在请求体中,因为 POST 方法的请求信息是放置在请求数据中的,所以它的请求信息是没有长度限制的
    • post会产生两个TCP数据包,浏览器会先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok(返回数据)

Http 和 Rpc 的本质区别是什么

  • RPC(即Remote Procedure Call,远程过程调用)
  • HTTP(HyperText Transfer Protocol,超文本传输协议)
  • 前者是一种方法,后者则是一种协议
  • 两者都常用于实现服务,在这个层面最本质的区别是RPC服务主要工作在TCP协议之上(也可以在HTTP协议),而HTTP服务工作在HTTP协议之上。由于HTTP协议基于TCP协议,所以RPC服务天然比HTTP更轻量,效率更胜一筹

从浏览器输入到页面展现做了哪些操作

  • 在用户输入到展示的几秒钟里面,浏览器做了很多的操作,里面的细节有很多
  • 刚开始浏览器会对输入的url进行解析,提取出协议,主机名,路径等信息
    • 这里面涉及到http和https的一些概念,
    • 如果是https的话,为了安全,会去做一些处理
  • 接下来浏览器会将主机名转换成对应的ip,这个过程被称之为dns解析
    • 浏览器会首先检查本地的dns缓存,如果有匹配的ip直接进行访问,如果没有的话,会向dns服务器发送请求,来获取对应的IP地址
  • 转换成ip之后,浏览器会通过ip地址和端口号来与服务器建立tcp链接,这个过程是通过tcp的三次握手完成的,以确保双方可以正常通信
    • 第一次握手,客户端发送syn包到服务器,并且客户端进行syn_send状态,等待服务器确认
    • 第二次握手,服务器接收到syn包时,会发送一个syn+ack包给客户端,服务器进入syn_recv状态
    • 第三次握手,客户端接收到syn+ack包之后,向服务器发送确认ack的包,至此三次握手结束
  • 建立tcp连接之后,客户端与服务器就开始传输数据了
    • 首先浏览器会向服务器发送http请求,请求的内容包括方法,请求头部,和请求体等
    • 如果是get请求,请求体在url上
    • 请求头包括浏览器自带的请求头和自定义的请求头,自定义的请求头可以用于登陆等场景
    • 浏览器自带的请求头包括浏览器的一些信息,浏览器可接收的压缩算法,浏览器可接收的数据格式,content-type,accept等等
  • 服务器接收到浏览器发送的请求之后,会进行处理,包括读取数据库,处理一些业务逻辑,生成一些动态内容等
  • 服务器处理完请求,会对处理结果封装成http响应,包括状态码,响应头部,响应体等
    • 浏览器自带的响应头也包含content-type,除此之外还有返回数据的压缩算法格式等,服务器修改cookie时,通过set-cookie修改
  • 浏览器接收到服务器的响应后,会对这个响应进行解析,如果响应体是html文档,则会下载其中引用的其他资源,例如js,css,静态文件等
    • 响应结束之后,为了更彻底地释放双方的资源,引入了四次挥手
    • 四次挥手的时间,看是否设置了keep alive属性
    • 第一次挥手,客户端发送FIN报文,表示不再发送数据。原因是客户端完成了数据的发送,需要关闭到服务器的数据传输通道。
    • 第二次挥手,服务器发送ACK报文,确认收到客户端的关闭请求。原因是服务器需要确认收到关闭请求,并继续发送可能未完成的数据。
    • 第三次挥手,服务器发送FIN报文,表示不再发送数据。原因是服务器完成了数据的发送,需要关闭到客户端的数据传输通道。
    • 第四次挥手,客户端发送ACK报文,确认收到服务器的关闭请求。原因是客户端需要等待一段时间,确保所有数据都被接收和处理完毕。
  • 解析下载完资源之后,浏览器会将html解析器解析成dom树,然后使用css解析器将css文件解析成样式规则,接着,浏览器根据dom树和样式规则进行渲染,将页面内容显示在浏览器上
  • 解析完html和css之后,浏览器开始执行js文件,处理一些业务逻辑,这里也涉及到一些请求响应
  • html和css渲染是同步执行的,但中间如果遇到js的操作,不管是下载还是解析,都会阻塞整个html的渲染
  • js内部又分为同步任务和异步任务,异步任务又分为宏任务和微任务,像promise就是微任务
  • 最后浏览器根据渲染结果将页面呈现给用户
  • 在请求和响应的过程中,中间还有一个很重要的步骤,就是浏览器的缓存
    • 浏览器的缓存主要包括强制缓存和协商缓存,强制缓存的判断主要在客户端,协商缓存的判断主要在服务端
    • 强制缓存主要使用cache-control,浏览器初次请求到服务器时,服务器不止返回资源,还会返回一个cache-control,客户端如果看到有这个标识,会将资源缓存下来,后面请求的时候会看这个标识是否过期,不过期的话就不进行请求
    • 协商缓存主要使用last-modified和etag进行标识,服务端会对客户端请求的资源进行判断,如果请求的资源时一样的,就会返回304,否则就会返回200
    • http缓存不一定只用一种方式,经常会一起使用,这时候就要了解两种缓存的执行流程
    • 发送http请求,一般来说,首先是判断是否命中强制缓存,再判断是否命中协商缓存,如果有强制缓存,但缓存过期,就会进入协商缓存的过程,如果服务端判断缓存不可用,即没有last-modified和etag标识或者标识不一致,就不会命中协商缓存,手动刷新的时候,协商缓存还是有效的,只有强制刷新,才能使两个缓存都失效

DNS 解析的时候有的是递归有的是迭代,为什么要这么设计?为什么不能都是迭代或者都是递归?哪一种比较好?

  • ‌DNS解析中递归和迭代设计的核心原因‌是为了简化客户端的操作和提高查询效率。递归查询由DNS服务器负责处理所有查询细节,客户端只需要发送一次查询请求;而迭代查询则需要客户端多次发送查询请求,并根据DNS服务器返回的引用信息自行决定下一步查询的目标。递归查询的优势在于简化了客户端的查询过程,减轻了客户端的负担,并提高了查询效率‌。
  • 递归查询的原理和优势‌在于客户端向本地名称服务器发出查询请求,本地名称服务器负责向其他DNS服务器递归地发出查询请求,直到找到所需的IP地址或者得到一个错误响应。递归查询简化了客户端的查询过程,客户端只需要发送一次查询请求,DNS服务器负责处理所有查询细节,包括利用缓存机制避免重复查询,从而提高查询效率‌
  • ‌迭代查询的原理和优势‌在于客户端向DNS服务器发送查询请求,DNS服务器返回一个指向其他DNS服务器的引用,客户端再向这个引用指向的DNS服务器发送查询请求,直到找到所需的IP地址或者得到一个错误响应。迭代查询的优势在于客户端可以根据DNS服务器返回的引用信息自行决定下一步查询的目标,具有更大的灵活性‌
  • 为什么不能都是迭代‌的原因在于如果全部使用迭代查询,客户端需要自行处理所有的查询细节,这会增加客户端的负担,降低查询效率。递归查询由DNS服务器集中处理所有查询细节,可以更好地利用缓存机制,避免重复查询,提高整体的网络访问速度和效率‌