Java八股文——计算机网络「网络场景篇」

发布于:2025-06-20 ⋅ 阅读:(15) ⋅ 点赞:(0)

描述一下打开百度首页后发生的网络过程

在这里插入图片描述

图片来自小林 coding

面试官您好,当我们在浏览器地址栏输入www.baidu.com并按下回车后,直到看到百度首页,这背后其实发生了一场跨越了整个TCP/IP协议栈的、极其精密和复杂的“数据之旅”

这个旅程,我通常会把它分为以下几个大的阶段:

第一阶段:应用层的准备 —— “翻译地址与准备信件”
  1. URL解析与转义

    • 首先,浏览器会解析我们输入的URL,确定协议是HTTP还是HTTPS,主机名是www.baidu.com,以及请求的资源路径。
    • 它还会检查URL中是否有非法字符,并进行必要的转义。
  2. DNS解析 (将域名翻译成IP地址)

    • 计算机在网络上通信,靠的是IP地址,而不是域名。所以,浏览器必须先找到www.baidu.com对应的IP地址。
    • 缓存检查(由近及远)
      a. 它会先查看浏览器自身的DNS缓存
      b. 如果没有,就查看操作系统的DNS缓存(比如hosts文件)。
      c. 如果还没有,就向本地DNS服务器(通常由ISP提供)发起请求。
    • 递归与迭代查询:如果本地DNS服务器也没有缓存,它就会启动一个从根DNS服务器 -> .com顶级域DNS服务器 -> baidu.com权威DNS服务器的逐级查询过程,最终获取到百度的IP地址。
第二阶段:传输层与网络层的准备 —— “建立可靠的通话线路”

现在,我们有了“收件人”的IP地址,需要建立一条可靠的通信管道。

  1. ARP协议获取MAC地址

    • IP地址用于在整个互联网中寻址,而MAC地址则用于在同一个局域网(LAN) 内进行通信。
    • 浏览器需要将数据包发给网关(路由器),让它帮忙转发出去。因此,它会通过ARP协议,在局域网内广播:“谁是网关IP xxx.xxx.xxx.xxx?请告诉我你的MAC地址。”
    • 网关收到后,会回复自己的MAC地址。
  2. TCP三次握手 (建立连接)

    • 浏览器(客户端)会向百度的IP地址和HTTP/HTTPS的默认端口(80/443),发起一个TCP连接请求
    • 通过经典的 “SYN -> SYN+ACK -> ACK” 的三次握手过程,客户端和服务器之间就建立起了一条可靠的、全双工的TCP连接通道
  3. (如果是HTTPS) TLS握手 (加密通道)

    • 如果访问的是HTTPS,那么在TCP连接建立之后,还需要进行一次SSL/TLS的握手
    • 这个过程,双方会验证服务器证书的真伪,并协商出一个用于后续通信的对称加密密钥,确保所有传输的数据都是加密的、安全的。
第三阶段:HTTP通信 —— “正式收发信件”
  • 发送HTTP请求

    • 现在,万事俱备。浏览器会构造一个HTTP请求报文(比如GET / HTTP/1.1 ...),并通过刚刚建立好的、安全的TCP连接,发送给百度服务器。
  • 服务器处理与响应

    • 百度的服务器(通常是Nginx等Web服务器)接收到请求后,可能会进行负载均衡,将请求转发给后端的业务服务器。
    • 业务服务器处理请求,生成要返回的HTML页面内容
    • 然后,服务器会构造一个HTTP响应报文(比如HTTP/1.1 200 OK ...),将HTML内容放在响应体中,再通过TCP连接返回给浏览器。
第四阶段:浏览器渲染页面
  1. 解析HTML:浏览器在收到HTML响应后,开始从上到下解析,构建DOM树
  2. 请求额外资源:在解析过程中,如果遇到<img>, <link rel="stylesheet">, <script>等标签,浏览器会发现还需要加载图片、CSS、JavaScript等额外资源。
  3. 并发请求:浏览器会再次、并发地发起多个HTTP请求,去获取这些资源。在HTTP/1.1的长连接下,它会复用之前建立的TCP连接;在HTTP/2下,它会在一个连接上多路复用这些请求。
  4. 构建渲染树与绘制:当CSS加载并解析完成后,会与DOM树合并,构建成渲染树(Render Tree)。然后,浏览器进行布局(Layout)和绘制(Paint),最终,我们将会在屏幕上看到五彩斑斓的百度首页。
  5. TCP四次挥手:当所有资源都加载完毕,并且连接空闲了一段时间后,浏览器或服务器会发起TCP四次挥手,优雅地关闭连接。

这一整套流程,就是我们按下回车后,在背后发生的、横跨了整个网络协议栈的壮丽史诗。


网页非常慢转圈圈的时候,要定位问题需要从哪些角度?

面试官您好,当遇到“网页打开很慢,一直在转圈”这种问题时,我会遵循一个自底向上、由近及远的系统性排查思路,来逐步缩小问题的范围,最终定位到根源。

这个排查过程,可以分为以下几个大的步骤:

第一步:界定问题范围 —— 是“我的问题”还是“别人的问题”?

正如您所说,第一步是确定故障的大致范围。

  1. 检查自身网络连通性
    • 我会先尝试访问几个其他的、公认稳定的大网站(如baidu.com, google.com)。
    • 如果都打不开:那大概率是我本地的网络环境出了问题。我会检查:
      • 物理连接:Wi-Fi是否连接正常?网线是否插好?
      • 本地网络配置:IP地址、DNS服务器配置是否正确?
      • 路由器/光猫是否工作正常?
    • 如果其他网站都能正常、快速地打开:那就排除了我本地网络的问题,说明问题出在从我这里,到目标网站的这条链路上,或者是目标网站本身
第二步:网络层面的排查 —— “路通不通?”

现在,我会开始使用网络工具,按照网络协议栈的层次,从下往上进行排查。抓包(使用Wiresharktcpdump 是这个阶段最核心、最有效的手段。

  1. DNS解析是否成功?

    • 排查点:首先,要看我们的计算机是否能把网站的域名,成功解析成IP地址
    • 如何排查
      • 在抓包结果中,筛选dns协议,看是否有正常的DNS查询和响应。
      • 或者直接使用nslookup www.target.comdig www.target.com命令,看能否返回IP地址。
    • 可能的问题
      • 如果解析失败,可能是域名输错了,或者本地DNS服务器出了问题。
      • 如果解析很慢,可能是本地DNS缓存污染,或者DNS服务器响应慢。
  2. TCP连接是否能建立?(三次握手)

    • 排查点:在拿到IP地址后,我们的浏览器需要与服务器建立一个TCP连接。
    • 如何排查:在抓包结果中,筛选tcp协议,并重点观察三次握手的过程。
    • 可能的问题
      • 只看到SYN包发出,但收不到SYN+ACK:这通常意味着我们的请求包,在去往服务器的路上被防火墙拦截了,或者服务器因为负载过高、遭受SYN Flood攻击等原因,无法响应。
      • 能看到SYN+ACK,但连接最终失败:可能是网络不稳定,或者中间网络设备有问题。
第三步:应用层面的排查 —— “服务器说了什么?”

如果TCP连接能成功建立,说明网络通路是基本正常的。问题就出在HTTP/HTTPS这个层面了。

  1. HTTP请求是否已发送?响应是什么?
    • 排查点:在抓包结果或浏览器开发者工具(F12)的“网络(Network)”面板中,查看HTTP的交互。
    • 可能的问题
      • 请求长时间处于“Pending”状态:这可能意味着浏览器因为同域名下的连接数限制,正在等待一个可用的TCP连接。
      • 服务器长时间不返回响应(TTFB过长):这明确地指向了服务器端性能瓶颈。可能是数据库慢查询、后端代码逻辑复杂、或者服务器负载过高导致的。此时,就需要去排查服务器端的日志和性能监控了。
      • 服务器返回了错误的状态码
        • 4xx客户端错误:如404 Not Found(URL路径错了)、403 Forbidden(没权限)、401 Unauthorized(没登录)。
        • 5xx服务器端错误:如500 Internal Server Error(服务器代码Bug)、502 Bad Gateway(网关或代理问题)、504 Gateway Timeout(上游服务超时)。
第四步:前端与网络质量排查 —— “数据回来了,为什么还慢?”

如果服务器很快地返回了200 OK和HTML内容,但页面依然在转圈,那么问题可能出在以下几个方面:

  1. 前端渲染问题

    • 正如您提到的,可能是JavaScript代码执行出错,阻塞了页面的渲染。此时需要查看浏览器控制台的报错信息。
    • 也可能是页面需要加载的资源(JS, CSS, 图片)过多、过大,或者这些资源所在的CDN节点很慢。
  2. 网络质量问题(丢包与重传)

    • 排查点:网络链路虽然通,但质量很差
    • 如何排查:在抓包结果中,观察是否有大量的TCP重传(Retransmissions)重复的ACK等现象。
    • 原因:大量的丢包和重传,会导致数据传输的实际速度非常慢,即使服务器响应很快,数据也迟迟无法完整地到达浏览器。

总结一下,我的排查思路就是这样一个自外而内、逐层深入的过程:先看自己 -> 再看路(DNS/TCP)-> 再看对方(HTTP)-> 最后看数据传输质量和前端渲染。通过这样系统性的分析,绝大多数的“转圈圈”问题,都能被精准地定位到。


Server A和Server B,如何判断两个服务器正常连接?出错怎么办?

面试官您好,您提出的这个问题非常好,它涉及到在分布式系统中,如何判断两个服务之间的连接是否健康、有效,以及在出现问题时如何处理。

要判断两个服务器(我们称之为A和B)之间的TCP连接是否正常,并处理异常,我们通常有两种层面的解决方案:应用层心跳TCP层Keepalive

方案一:应用层心跳 (Application-Level Heartbeat) —— 最常用、最灵活的方案

这是我们在实践中最常用、也最推荐的方式。

  • 如何实现?

    1. 在A和B之间建立连接后,由一方(比如客户端A)定期地(比如每隔5秒)向另一方(服务器B)发送一个自定义的、非常小的“心跳”数据包。这个包的内容可以很简单,比如就是一个字符串"ping"
    2. 服务器B在收到心跳包后,立即回复一个对应的“心跳响应”(比如"pong")。
    3. 判断逻辑
      • 发送方(A):如果在发送了N次心跳包后(比如连续3次),都没有收到对方的pong响应,那么A就可以单方面地认为这个连接已经失效,或者B服务已经无响应了。此时,A应该主动关闭这个连接,并尝试进行重连或将B节点标记为不可用。
      • 接收方(B):同样,如果B在超过一个约定的时间(比如超过3个心跳周期,即15秒)都没有收到来自A的任何心跳包,那么B也可以认为A已经“失联”,然后主动关闭这个连接以释放资源。
  • 优点

    • 灵活性极高:心跳的频率、超时时间、重试次数等,都可以在我们的应用程序中完全自定义,可以根据业务对实时性的要求,设置得非常灵敏(比如1秒一次)。
    • 能检测应用层面的“假死”:即使底层的TCP连接是通的,但如果服务器B的业务逻辑卡死了,无法响应心跳,客户端A也能及时地发现。
  • 应用:几乎所有的RPC框架(如Dubbo)、消息队列(如RocketMQ)、数据库连接池,其内部都实现了应用层的心跳保活机制。

方案二:TCP Keepalive机制 —— 内核级的“兜底”方案

这是TCP协议自身提供的一种连接保活机制,由操作系统内核来管理。

  • 它解决了什么问题?

    • 它主要是为了解决 “半打开连接” 的问题。比如,客户端A突然断电宕机,它无法向服务器B发送任何关闭连接的FIN包。此时,在服务器B看来,这个TCP连接依然处于ESTABLISHED状态,它会永远地等待下去,造成资源泄漏
  • 如何工作?

    1. 我们可以通过Socket选项来开启TCP Keepalive。
    2. 当一个连接上长时间没有任何数据交互时(这个“长时间”在Linux上默认是2小时tcp_keepalive_time),内核会自动介入。
    3. 内核会发送一个 “保活探测包”(Keepalive Probe) 给对端。这个包不包含任何应用数据。
    4. 判断逻辑
      • 如果收到对方的ACK响应,说明连接还活着,计时器重置。
      • 如果没有收到响应,内核会每隔一段时间(默认75秒,tcp_keepalive_intvl重试一次。
      • 连续重试多次(默认9次,tcp_keepalive_probes)后,如果依然没有任何响应,内核就会最终认定这个连接已经死亡。
    5. 处理:内核会强制关闭这个连接(类似发送RST),并通知上层应用程序连接已断开。
  • 缺点

    • 默认超时时间太长:默认2小时的空闲时间才开始探测,对于绝大多数需要快速感知故障的互联网应用来说,太慢了,不实用
    • 不感知应用层状态:它只能检测到TCP层面的连接存活,无法感知到应用进程是否已经卡死。
总结与选型
特性 应用层心跳 TCP Keepalive
实现层面 应用程序 操作系统内核
灵活性 (频率、超时可自定义) 低 (全局内核参数)
探测实时性 (可达秒级) 低 (默认小时级)
感知能力 可感知应用“假死” 只能感知TCP连接存活
主要用途 主动、快速的连接健康检查 被动的、兜底的僵尸连接清理

在实践中,我们通常会优先使用应用层心跳,因为它更可控、更灵敏,能更好地满足业务对高可用和快速故障发现的需求。而TCP Keepalive,则更多地是作为一个最后的、底层的“保险丝”,来清理那些因各种意外而产生的、长时间无人问津的“僵尸连接”。


服务端正常启动了,但是客户端请求不到有哪些原因?如何排查?

面试官您好,当遇到“客户端请求不到已启动的服务端”这类问题时,我会遵循一个从网络连通性到应用层逻辑的、逐层排查的思路,来系统地定位问题根源。

这个问题可以分为两大类情况。

第一类:请求完全失败,没有任何响应(如连接超时、无法访问)

这种情况,通常意味着问题出在网络层或传输层,即客户端和服务器之间 “路不通”。我会按照以下顺序进行排查:

  1. 第一步:检查网络基础配置(客户端侧)

    • IP地址和端口号是否正确? 这是最基本、但也最容易出错的地方。我会仔细核对请求的IP和Port是否与服务端监听的完全一致。
    • 本地网络是否正常? 我会先ping一个公认的地址(如ping baidu.com)来确认我自己的机器网络是通的。
    • 是否设置了网络代理? 检查我的浏览器或测试工具,是否配置了HTTP代理,而这个代理本身可能无法访问目标服务器。
  2. 第二步:检查网络连通性(端到端)

    • ping <服务器IP>:首先,用ping命令检查我本地到服务器之间的网络路由是否可达。如果ping不通,说明中间可能存在网络设备故障或路由配置问题。
    • telnet <服务器IP> <端口号>:这是最关键的一步。ping通只能说明网络可达,但不能保证端口是开放的。telnet可以精确地测试服务器的特定端口是否在监听
      • 如果telnet连接成功(黑屏),说明网络链路和服务器端口都是通的,问题很可能在应用层。
      • 如果telnet连接超时或被拒绝,那么问题几乎可以锁定在防火墙服务器应用本身
  3. 第三步:检查防火墙与安全组(服务端侧)

    • 如果telnet不通,我会首先怀疑防火墙
    • 服务器防火墙:登录服务器,检查其自身的防火墙(如Linux的iptablesfirewalld)是否开放了对应的端口。
    • 云服务商安全组:如果服务器部署在云上(如阿里云、AWS),还需要检查其安全组规则,是否允许我的客户端IP地址访问目标端口。这是非常常见的被忽略的点。
第二类:请求有响应,但返回的是错误状态码

这种情况,说明网络链路是通的,问题出在应用层。我会根据返回的具体HTTP状态码,进行针对性的排查。

  • 400 Bad Request:我会检查我发送的请求参数,比如JSON格式是否正确、请求头是否缺失、参数类型是否匹配等。

  • 401 Unauthorized:我会检查我的请求是否携带了正确的认证信息,比如请求头中的Authorization Token是否有效、是否过期。

  • 403 Forbidden:如果认证信息是正确的,但依然返回403,我会去检查:

    • 当前用户的角色和权限,是否足以访问这个接口。
    • 服务器或中间件(如Nginx、Tomcat)是否有IP白名单或访问控制的配置,拒绝了我的请求。
  • 404 Not Found:这是最常见的错误之一。我会检查:

    • 请求的URL路径是否拼写正确。
    • 服务器的应用**上下文路径(Context Path)**是否配置正确。
    • 后端的Controller中,对应的**@RequestMapping路径**是否匹配。
  • 500 Internal Server Error

    • 看到500,就意味着问题100%出在服务端
    • 我会立即登录服务器,查看应用程序的错误日志(Error Log)。日志中通常会明确地打印出异常堆栈,比如空指针、数据库异常等,根据日志就能快速定位到代码中的Bug。
  • 502/503/504 (网关相关错误)

    • 如果架构中使用了Nginx等反向代理,出现这些错误,通常意味着Nginx与后端的Tomcat等应用服务器之间的通信出了问题
    • 我会去检查:
      • 后端应用服务是否已经宕机或正在重启
      • 后端服务是否因为负载过高、GC停顿等原因,导致处理请求过慢,从而引发了Nginx的网关超时。

通过这样一套从网络到应用、从客户端到服务端的、结构化的排查流程,绝大多数的“请求不通”问题,都能被高效地定位和解决。


服务器ping不通但是HTTP能请求成功,会出现这种情况吗?什么原因造成的?

面试官您好,您提出的这个问题非常好,它揭示了网络连通性测试的一个常见“陷阱”。

答案是:会的,这种情况完全可能出现,而且在生产环境中相当常见。

1. 根本原因:ping和HTTP使用了不同的网络协议

这个现象的根本原因在于,ping命令和HTTP请求,在网络协议栈的传输层和网络层,走的是完全不同的路径。

  • ping命令:它使用的是ICMP协议(Internet Control Message Protocol,互联网控制报文协议)。ICMP的主要作用,是在IP主机、路由器之间传递控制消息,比如网络是否可达、主机是否可访问等。它更像是一个网络的“侦察兵”或“诊断工具”。

  • HTTP请求:它工作在应用层,而其底层的传输,依赖的是TCP协议。我们访问一个网页,是建立在一次完整的TCP连接之上的。

所以,“ping不通”只代表了服务器的ICMP端口对我们不可达,但这完全不代表它的TCP端口也不可达。

2. 最常见的原因:服务器防火墙策略

防火墙策略,是导致这种情况最核心、最常见的原因。

  • 为什么会这么配置?

    • 出于安全考虑,很多服务器的系统管理员或云服务商,会配置非常严格的防火墙或安全组规则。
    • ICMP协议,虽然对网络诊断很有用,但它也可能被用于一些网络攻击,比如ICMP扫描(用于探测网络拓扑和存活主机)ICMP洪水攻击(Smurf Attack)
    • 因此,一个常见的安全实践就是,在服务器的防火墙上,“一刀切”地禁用所有传入的ICMP请求,即“禁止ping”。
    • 但是,为了让Web服务能够正常工作,它又必须明确地开放TCP的80端口(HTTP)和443端口(HTTPS)
  • 最终结果

    • 当我们ping这台服务器时,我们的ICMP请求包,在到达服务器后,被其防火墙直接丢弃了,所以我们永远收不到回应,表现为“ping不通”。
    • 但当我们用浏览器访问它的网页时,我们的TCP连接请求,因为其目标端口是80或443,被防火墙允许通过,所以能够正常建立连接,HTTP请求也能成功。
3. 其他可能的原因

虽然防火墙是主要原因,但也存在其他一些可能性:

  • 负载均衡器的配置:一些负载均衡器(如LVS)可能被配置为只转发特定TCP/UDP端口的流量,而不会响应或转发ICMP请求。
  • 操作系统内核参数:在Linux中,也可以通过内核参数(如net.ipv4.icmp_echo_ignore_all)来全局禁用对ping请求的响应。
反向思考:Ping得通,但HTTP不通

反过来,“ping得通,但HTTP不通” 也是非常常见的故障场景。这通常意味着:

  • 网络链路是通的,ICMP协议也是允许的。
  • 但服务器的80/443端口没有被监听(比如Web服务没启动、或者监听在了错误的端口上),或者防火墙阻止了对这个特定端口的访问

总结一下ping只是一个基础的网络连通性探测工具,它的成功与否,并不能完全等同于特定应用服务的可用性。在排查网络问题时,我们应该使用更具针对性的工具,比如用telnet <ip> <port>来测试特定端口的TCP连通性,这比ping要可靠得多。

参考小林 coding


网站公告

今日签到

点亮在社区的每一天
去签到