计算机网络面试题
更新: 8/21/2025 字数: 0 字 时长: 0 分钟
常见的 HTTP 状态码有哪些?
HTTP 状态码是服务器对请求的响应结果,由三位数字组成,第一位数字定义了响应的类别。以下是一些最常见和重要的 HTTP 状态码:
1xx - 信息响应(Informational responses):表示请求已被接收,继续处理。
状态码 名称 描述 常见应用场景 100 Continue 客户端应继续发送请求 大文件上传前,客户端检查服务器是否接受请求 101 Switching Protocols 服务器已切换协议 WebSocket 连接建立 2xx - 成功响应(Successful responses):表示请求已被成功接收、理解、接受。
状态码 名称 描述 常见应用场景 200 OK 请求成功,最常见的状态码 页面加载、API 请求成功 201 Created 请求已成功,并创建了新的资源 创建用户、提交文章等 POST 请求 202 Accepted 请求已接受处理,但处理尚未完成 异步处理,如排队任务 204 No Content 请求成功,但响应报文不含实体的主体部分 删除操作、PUT 更新后无新内容返回 206 Partial Content 客户端进行了范围请求,服务器成功执行了这部分的 GET 请求 文件断点续传、视频分段加载 3xx - 重定向(Redirection messages):表示需要采取进一步操作才能完成请求。
状态码 名称 描述 常见应用场景 301 Moved Permanently 永久重定向。资源已永久地移动到新 URI 网站域名变更、HTTP 到 HTTPS 重定向 302 Found 临时重定向。资源临时地移动到新 URI 临时页面调整、负载均衡 303 See Other 告知客户端使用 GET 方法访问另一个 URI 来获取资源 POST 请求后,引导用户查看结果页面 304 Not Modified 协商缓存命中。资源未修改,客户端可使用缓存版本 浏览器缓存优化 307 Temporary Redirect 临时重定向。与 302 类似,但要求客户端继续使用相同的 HTTP 方法 临时页面调整(保留方法) 308 Permanent Redirect 永久重定向。与 301 类似,但要求客户端继续使用相同的 HTTP 方法 域名变更(保留方法) 4xx - 客户端错误(Client error responses):表示客户端发送的请求包含错误或无法完成。
状态码 名称 描述 常见应用场景 400 Bad Request 客户端请求有语法错误,不能被服务器理解 请求参数错误、格式不正确 401 Unauthorized 请求需要用户认证 访问受保护资源未提供认证信息 403 Forbidden 服务器已理解请求,但拒绝执行(通常是权限问题) 无权访问、IP 被禁止 404 Not Found 请求的资源不存在。最常见的错误状态码 URL 路径错误、资源已被删除 405 Method Not Allowed 请求方法(如 GET, POST)不被允许用于请求的资源 对不支持 POST 的接口发送 POST 请求 408 Request Timeout 客户端在服务器等待请求时,没有在允许的时间内完成发送请求 客户端网络问题,请求发送超时 409 Conflict 请求与服务器的当前状态冲突 并发修改冲突(如乐观锁)、资源已存在 413 Payload Too Large 请求的实体过大,服务器无法处理 上传文件过大 415 Unsupported Media Type 请求的媒体类型(Content-Type)不被服务器支持 发送了服务器不支持的 Content-Type 429 Too Many Requests 客户端在给定时间内发送了太多请求(速率限制) 短时间内大量请求,被服务器限流 5xx - 服务器错误(Server error responses):表示服务器在尝试处理请求时发生了错误。
状态码 名称 描述 常见应用场景 500 Internal Server Error 服务器遇到了一个意外情况,阻止其完成请求。最常见的服务器端错误 后端代码错误、服务器配置问题 501 Not Implemented 服务器不支持请求的功能,无法完成请求 请求了服务器未实现的 API 502 Bad Gateway 作为网关或代理工作的服务器收到了上游服务器的无效响应 网关与后端服务通信失败 503 Service Unavailable 服务器目前无法处理请求,通常是由于服务器过载或停机维护 服务器维护、流量高峰导致服务崩溃 504 Gateway Timeout 作为网关或代理工作的服务器未能及时从上游服务器或某些辅助服务器接收响应 网关等待后端服务响应超时
HTTP 请求包含哪些内容,请求头和请求体有哪些类型?
HTTP 请求由三个主要部分组成:
- 请求行 (Request Line):包含请求方法、请求 URI 和 HTTP 协议版本。
GET /index.html HTTP/1.1
- 请求头 (Request Headers):包含客户端环境信息、请求体信息、认证信息等。键值对形式。
- 空行 (Blank Line):用于分隔请求头和请求体。
- 请求体 (Request Body):包含客户端发送给服务器的数据,通常在 POST、PUT 等方法中出现。
请求头 (Request Headers) 的类型
请求头包含各种元数据,用于描述请求的上下文。一些常见的请求头类型:
- 通用头 (General Headers):既可用于请求又可用于响应,例如
Connection: keep-alive
(保持连接)Cache-Control: no-cache
(不使用缓存)
- 请求头 (Request Headers):仅用于请求,提供更多关于请求或客户端的信息,例如
Host: www.example.com
(请求的目标主机)User-Agent: Mozilla/5.0 (...)
(客户端代理信息,通常是浏览器信息)Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
(客户端可接受的媒体类型)Accept-Language: zh-CN,zh;q=0.8
(客户端可接受的语言)Accept-Encoding: gzip, deflate, sdch
(客户端可接受的编码方式)Cookie: key=value
(客户端发送给服务器的 Cookie)Referer: http://www.example.com/previous-page.html
(请求的来源页面)Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
(认证信息,如 Basic Auth, Bearer Token)If-Modified-Since: Tue, 15 Nov 1994 12:45:26 GMT
(用于条件请求,协商缓存)
- 实体头 (Entity Headers):描述请求体或响应体的资源信息,例如
Content-Type: application/json
(请求体的媒体类型)Content-Length: 123
(请求体的字节长度)
请求体 (Request Body) 的类型
请求体用于承载客户端需要发送给服务器的数据。其类型主要由 Content-Type
请求头指定。常见的请求体类型包括:
application/x-www-form-urlencoded
:- 描述:最常见的表单提交方式。数据被编码成键值对,用
&
分隔,键和值之间用=
连接,特殊字符会被编码。 - 示例:
name=Alice&age=30
- 场景:传统的 HTML 表单
method="POST"
且不指定enctype
时的默认类型。
- 描述:最常见的表单提交方式。数据被编码成键值对,用
multipart/form-data
:描述:用于提交包含文件(二进制数据)的表单。每个表单字段或文件都被分成独立的部分(part),用一个分隔符(boundary)隔开。
示例:
txtContent-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW ------WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="username" Alice ------WebKitFormFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="profile_picture"; filename="me.jpg" Content-Type: image/jpeg ... (binary image data) ... ------WebKitFormBoundary7MA4YWxkTrZu0gW--
场景:HTML 表单
method="POST"
且enctype="multipart/form-data"
时,常用于文件上传。
application/json
:- 描述:以 JSON 格式传输数据。这是现代 Web API 和前后端分离应用中最常用的数据交换格式。
- 示例:
{"name": "Bob", "age": 25}
- 场景:RESTful API 调用,前端(如 React, Vue, Angular)通过 AJAX/Fetch 发送数据到后端。
text/plain
:- 描述:纯文本数据,不进行任何特殊编码或格式化。
- 示例:
Hello, this is plain text.
- 场景:不常用,有时用于发送简单的文本信息,或者调试。
application/xml
或text/xml
:- 描述:以 XML 格式传输数据。在某些传统企业级应用或 SOAP 服务中仍有使用。
- 示例:
<user><name>Charlie</name><age>35</age></user>
- 场景:老旧的 Web Service (SOAP)。
二进制数据 (Binary Data):
- 描述:直接传输原始的二进制数据,没有特定的结构,
Content-Type
会是具体的媒体类型,如image/jpeg
,audio/mpeg
,application/octet-stream
(通用二进制流)。 - 示例:直接的图片、音频、视频文件内容。
- 场景:直接上传文件内容,而不是通过
multipart/form-data
封装。
- 描述:直接传输原始的二进制数据,没有特定的结构,
HTTP 中 GET 和 POST 的区别是什么?
GET 和 POST 是 HTTP 协议中最常用的两种请求方法,它们在语义、用途、数据传输方式、安全性等方面存在显著区别:
特性 | GET 请求 | POST 请求 |
---|---|---|
语义/用途 | 获取/检索 资源。通常用于从服务器请求数据。 | 提交/创建/更新 资源。通常用于向服务器发送数据以进行处理。 |
幂等性 | 幂等:多次请求同一个 GET URL,只要资源未改变,结果都是相同的,不会对服务器状态造成副作用。 | 非幂等:多次提交相同的 POST 请求可能会导致不同的结果(例如,每次提交都会创建新的资源)。 |
安全性 | 不安全:不是指数据加密,而是数据以明文显示在 URL 中,容易被浏览器历史记录、服务器日志、代理服务器缓存。不适合传输敏感信息。 | 相对安全:数据放在请求体中,URL 中不显示,因此不会被浏览器历史记录、服务器日志直接记录,但数据本身也不是加密的。 |
可见性 | 参数通过 URL 的查询字符串 传输,在地址栏可见。 | 参数通过 请求体 传输,在地址栏不可见。 |
数据长度限制 | 有限制:URL 的长度通常有浏览器和服务器的限制(通常在 2KB - 8KB 之间)。 | 无限制:请求体的大小理论上没有限制,只受服务器处理能力和内存的限制。 |
缓存 | 可以缓存:浏览器和代理服务器可以缓存 GET 请求的响应,以提高性能。 | 不能缓存:POST 请求的响应默认不能被缓存。 |
历史记录/收藏 | 可以收藏/添加到书签:因为请求参数包含在 URL 中。 | 不能收藏/添加到书签:因为请求体中的数据不会被保存。 |
回退/刷新 | 回退和刷新页面无副作用。 | 回退或刷新页面时,浏览器通常会提示用户是否重新提交表单,因为重复提交可能导致副作用。 |
总结:
- GET 主要用于获取数据,不应改变服务器状态,数据放在 URL 中。适合查询、获取列表、查看详情等操作。
- POST 主要用于提交数据,通常会改变服务器状态(如创建新用户、提交订单),数据放在请求体中。适合创建、更新、删除等操作。
HTTP 1.0 和 2.0 有什么区别?
HTTP/1.0 是一个连接在每次请求/响应后都会关闭的协议。这意味着如果客户端请求了网页及其所有图片,它将为每个图片文件建立一个新的连接。
HTTP/2.0 是基于 SPDY 协议的,旨在解决 HTTP/1.x 的性能瓶颈。它引入了多项关键特性来提高 Web 性能。
主要区别:
多路复用(Multiplexing):
- HTTP/1.0:一次连接只能处理一个请求。如果需要发送多个请求,就必须建立多个 TCP 连接,或者等待当前请求响应后才能发送下一个请求(队头阻塞)。
- HTTP/2.0:引入了二进制分帧层。它允许在同一个 TCP 连接上同时发送多个请求和响应。每个请求/响应都被分成更小的帧,可以独立发送、乱序到达,然后在另一端重新组装,这解决了队头阻塞(Head-of-Line Blocking)问题。
二进制分帧(Binary Framing):
- HTTP/1.0:基于文本协议,头部信息冗余且解析效率低。
- HTTP/2.0:采用二进制协议,所有通信都是二进制帧,更紧凑、更高效,解析也更快。
头部压缩(Header Compression):
- HTTP/1.0:每次请求都会发送完整的头部信息,即使很多头部字段都是重复的,浪费带宽。
- HTTP/2.0:使用 HPACK 算法对头部进行压缩。它维护一个共享的静态和动态表,只发送头部字段的增量或索引,大大减少了头部开销。
服务器推送(Server Push):
- HTTP/1.0:客户端发起请求后,服务器只能返回所请求的资源。如果该资源依赖其他资源(如 HTML 文件依赖 CSS 和 JS),客户端需要解析完 HTML 后再发起额外的请求。
- HTTP/2.0:服务器可以在客户端明确请求之前,主动将一些它预测客户端会需要的资源(如 CSS、JS、图片)推送给客户端。这减少了客户端 - 服务器往返次数,提高了加载速度。
请求优先级(Request Prioritization):
- HTTP/1.0:无法为请求设置优先级。
- HTTP/2.0:客户端可以为请求设置优先级,服务器可以根据这些优先级决定发送响应的顺序,确保关键资源优先传输。
连接管理:
- HTTP/1.0:短连接,每个请求都会建立新的 TCP 连接,开销大。
- HTTP/2.0:长连接,一个 TCP 连接可以承载多个并发请求,减少了 TCP 连接的建立和关闭开销。
总结表格:
特性 | HTTP/1.0 | HTTP/2.0 |
---|---|---|
连接模型 | 短连接(每个请求新连接) | 长连接(单一连接多请求) |
传输方式 | 文本协议 | 二进制分帧 |
并发性 | 串行请求,队头阻塞 | 多路复用,并行请求,解决队头阻塞(应用层) |
头部开销 | 无压缩,重复发送 | HPACK 压缩,减少开销 |
服务器推送 | 不支持 | 支持 |
请求优先级 | 不支持 | 支持 |
性能 | 较低 | 较高 |
HTTP 2.0 和 3.0 有什么区别?
HTTP/3.0 是 HTTP/2.0 的演进版本,其最显著的变化是放弃了 TCP 协议,转而使用基于 UDP 的 QUIC (Quick UDP Internet Connections) 协议。
主要区别:
底层传输协议:
- HTTP/2.0:基于 TCP 协议。
- HTTP/3.0:基于 UDP 协议,并在此基础上实现了 QUIC 协议。
TCP 队头阻塞(Head-of-Line Blocking)的根本解决:
- HTTP/2.0:虽然通过多路复用解决了应用层的队头阻塞(一个连接上可以并行发送多个请求),但如果底层的 TCP 丢包,所有通过该 TCP 连接传输的数据流都会受影响,因为它必须等待丢失的包被重传,这就是 TCP 层面的队头阻塞。
- HTTP/3.0:QUIC 协议在 UDP 之上实现了自己的可靠传输、流量控制和拥塞控制。QUIC 的一个核心特性是它支持独立的流。即使一个流的某个数据包丢失,也只会影响这一个流,而不会阻塞同一连接上的其他流。这彻底解决了 TCP 带来的队头阻塞问题。
连接建立时间(握手延迟):
- HTTP/2.0:需要进行 TCP 三次握手,如果是 HTTPS,还需要额外的 TLS 握手(通常是 2-RTT 或 3-RTT)。
- HTTP/3.0:QUIC 协议将握手过程简化。
- 首次连接:可以一次性完成加密和传输协议的握手(1-RTT),甚至在某些情况下,如果客户端已经与服务器建立过连接,可以实现 0-RTT 握手(类似 TCP Fast Open),大大减少了连接建立时间。
- QUIC 的加密是内置的,它总是加密的。
连接迁移(Connection Migration):
- HTTP/2.0:TCP 连接是基于 IP 地址和端口号的。如果客户端的网络发生变化(例如从 Wi-Fi 切换到蜂窝网络,IP 地址会改变),TCP 连接会断开并需要重新建立,导致服务中断。
- HTTP/3.0:QUIC 连接是基于一个 Connection ID 的。客户端的 IP 地址或端口号变化时,只要 Connection ID 不变,连接就可以维持,而不需要重新建立连接,这对于移动设备尤其重要。
安全性:
- HTTP/2.0:通常与 TLS/SSL 结合使用,但 TLS 是一个独立层。
- HTTP/3.0:QUIC 协议本身就集成了 TLS 1.3 的加密能力,默认就是加密的,增强了安全性。
总结表格:
特性 | HTTP/2.0 | HTTP/3.0 |
---|---|---|
底层协议 | TCP | UDP (基于 QUIC) |
队头阻塞 | 应用层解决,但 TCP 层仍存在 | 根本解决(QUIC 的独立流) |
连接建立 | TCP + TLS 握手(2-3 RTT) | QUIC 握手(1-RTT,甚至 0-RTT) |
连接迁移 | 不支持(IP/端口改变需重连) | 支持(基于 Connection ID) |
安全性 | TLS 独立于 HTTP/2.0 实现 | QUIC 内置 TLS 1.3,默认加密 |
多路复用 | 支持(基于帧) | 支持(基于 QUIC 流) |
服务器推送 | 支持 | 支持 |
头部压缩 | HPACK | QPACK(基于 HPACK 改进,更适合乱序交付的 QUIC 流) |
应用场景 | 大部分 Web 服务 | 对延迟敏感、移动设备频繁切换网络的场景更优 |
HTTP 和 HTTPS 有什么区别?
HTTP 是一种用于分布式、协作式和超媒体信息系统的应用层协议。它是万维网数据通信的基础,以明文方式发送数据。
HTTPS 是 HTTP 的安全版本,通过在 HTTP 层和 TCP 层之间添加一个安全层(SSL/TLS),对通信数据进行加密,保证数据的完整性和隐私性。
主要区别:
安全性:
- HTTP:数据传输是明文的,不加密。这意味着传输的数据(如用户名、密码、信用卡信息)可以被第三方截获并直接读取,存在数据泄露和篡改的风险。
- HTTPS:数据传输是加密的。通过 SSL/TLS 协议对数据进行加密,即使数据被截获,也无法直接读取其内容,大大提高了数据传输的安全性、完整性和隐私性。
默认端口:
- HTTP:默认使用端口 80。
- HTTPS:默认使用端口 443。
连接方式:
- HTTP:直接与 TCP 连接。
- HTTPS:在 TCP 握手完成后,需要额外的 SSL/TLS 握手过程来建立加密通道。
证书:
- HTTP:不需要任何证书。
- HTTPS:需要 SSL/TLS 证书。这个证书由权威的第三方机构(CA,Certificate Authority)颁发,用于验证服务器的身份。客户端在访问 HTTPS 网站时,会验证服务器的证书是否合法有效,防止中间人攻击。
成本:
- HTTP:通常没有额外成本(除了域名和服务器)。
- HTTPS:需要购买和维护 SSL/TLS 证书(尽管现在有很多免费证书如 Let's Encrypt),并且服务器需要额外的计算资源进行加密解密,可能会略微增加服务器负载(但现代硬件影响很小)。
SEO(搜索引擎优化):
- HTTP:搜索引擎(尤其是 Google)会优先收录和排名使用 HTTPS 的网站,因为它们更安全,用户体验更好。HTTP 网站可能会被标记为“不安全”。
- HTTPS:对 SEO 友好,有助于提高网站的搜索排名。
显示方式:
- HTTP:浏览器地址栏通常显示为
http://
,并且可能会显示“不安全”的警告。 - HTTPS:浏览器地址栏通常显示为
https://
,并伴随一个锁形图标,表示连接是安全的。
- HTTP:浏览器地址栏通常显示为
SSL/TLS 握手过程简述(HTTPS 的核心):
- 客户端发起 Client Hello:客户端向服务器发送支持的 SSL/TLS 版本、加密算法套件列表、随机数等。
- 服务器响应 Server Hello:服务器从客户端提供的列表中选择一个最佳的加密套件、返回服务器的随机数、以及服务器的数字证书(包含公钥和服务器信息)。
- 客户端验证证书:客户端验证服务器证书的合法性、有效性(是否过期、是否由信任的 CA 颁发等)。如果验证失败,会发出警告。
- 客户端生成预主密钥:客户端生成一个随机的预主密钥(Pre-Master Secret),并使用服务器证书中的公钥对其进行加密。
- 客户端发送加密的预主密钥:客户端将加密后的预主密钥发送给服务器。
- 服务器解密预主密钥:服务器使用自己的私钥解密预主密钥。
- 生成会话密钥:客户端和服务器都使用客户端随机数、服务器随机数和预主密钥通过协商的算法生成相同的会话密钥(Session Key)。
- 加密通信:客户端和服务器后续的所有通信都将使用这个会话密钥进行对称加密和解密。
总结表格:
特性 | HTTP | HTTPS |
---|---|---|
安全性 | 明文传输,不安全 | 加密传输,安全(SSL/TLS) |
默认端口 | 80 | 443 |
证书 | 不需要 | 需要 SSL/TLS 证书 |
成本 | 低 | 相对高(证书费用,但有免费证书) |
SEO | 不利 | 有利 |
速度 | 理论上略快(无加密解密开销) | 理论上略慢(加密解密和握手开销),但现代硬件影响很小 |
身份验证 | 无 | 服务器身份验证(通过证书) |
TCP 和 UDP 有什么区别?
TCP 和 UDP 是互联网协议族中两种最主要的传输层协议。它们最核心的区别在于它们提供的服务特性不同:
特性 | TCP (传输控制协议) | UDP (用户数据报协议) |
---|---|---|
连接性 | 面向连接的协议:在数据传输前需要建立连接(三次握手),传输结束后需要释放连接(四次挥手)。 | 无连接的协议:数据传输前无需建立连接,直接发送数据报。 |
可靠性 | 可靠的:提供数据确认、重传、乱序重组、流量控制和拥塞控制机制,确保数据完整、有序、不重复地到达。 | 不可靠的:不提供数据确认、重传等机制。数据发出后,无法保证其是否到达、是否按序到达或是否重复。 |
顺序性 | 保证数据顺序:通过序列号保证数据包按发送顺序交付给应用层。 | 不保证数据顺序:数据包的到达顺序可能与发送顺序不同。 |
错误检测 | 通过校验和检测数据错误。 | 通过校验和检测数据错误。 |
流量控制 | 通过滑动窗口机制调节发送方发送速率,防止接收方被数据淹没。 | 不提供流量控制。 |
拥塞控制 | 通过慢启动、拥塞避免、快速重传、快速恢复等算法防止网络拥塞。 | 不提供拥塞控制。 |
传输速度 | 相对较慢,因为需要更多的开销(连接管理、确认、重传等)。 | 相对较快,因为没有连接管理和可靠性保障的开销,直接发送。 |
首部大小 | 较长,通常为 20 字节(无选项时)到 60 字节。 | 较短,固定为 8 字节。 |
应用场景 | 需要高可靠性、准确性和顺序性的应用,如: Web 浏览 (HTTP/HTTPS) 文件传输 (FTP) 电子邮件 (SMTP/POP3/IMAP) 远程登录 (SSH) | 对实时性要求高,允许少量数据丢失的应用,如: 实时音视频通信 (VoIP, Video Conferencing) 在线游戏 DNS 查询 SNMP (网络管理协议) |
总结:TCP 像打电话,需要先拨号建立连接,通话过程中确保信息传递无误;UDP 像寄明信片,写完就寄,不保证对方是否收到或收到多少张。
说说 TCP 的三次握手?
TCP 的三次握手是在客户端和服务器之间建立 TCP 连接的过程,其目的是为了初始化序列号并确认双方的发送和接收能力。
过程图示:
详细步骤解释:
第一次握手 (SYN):
- 客户端发送一个 TCP 同步报文段 (SYN) 到服务器。
- 报文段中包含:
SYN=1
(表示这是一个同步报文段,请求建立连接)seq=x
(客户端选择的初始序列号 ISN, Initial Sequence Number)
- 此时,客户端进入
SYN_SENT
状态。
第二次握手 (SYN-ACK):
- 服务器接收到客户端的 SYN 报文段后,如果同意建立连接,会发送一个 同步确认报文段 (SYN-ACK) 给客户端。
- 报文段中包含:
SYN=1
(表示这是一个同步报文段)ACK=1
(表示这是一个确认报文段)seq=y
(服务器选择的初始序列号 ISN)ack=x+1
(确认收到客户端的 SYN 报文段,并期望收到客户端下一个序列号为 x+1 的数据)
- 此时,服务器进入
SYN_RCVD
状态。
第三次握手 (ACK):
- 客户端接收到服务器的 SYN-ACK 报文段后,会再次发送一个 确认报文段 (ACK) 给服务器。
- 报文段中包含:
ACK=1
(表示这是一个确认报文段)seq=x+1
(这是客户端期望发送给服务器的下一个序列号)ack=y+1
(确认收到服务器的 SYN-ACK 报文段,并期望收到服务器下一个序列号为 y+1 的数据)
- 此时,客户端进入
ESTABLISHED
状态。 - 服务器接收到客户端的 ACK 报文段后,也进入
ESTABLISHED
状态。
至此,TCP 连接建立成功,双方可以开始进行数据传输。
为什么需要三次握手而不是两次?
最主要的原因是为了防止已经失效的连接请求报文段突然又传到服务器,从而导致服务器白白等待以及资源的浪费。
- 如果只有两次握手:客户端发送 SYN,服务器收到后回复 SYN-ACK,然后服务器就认为连接建立了。如果这个 SYN 是一个早已失效的请求(例如,客户端之前发送了一个 SYN,但由于网络延迟,很久之后才到达服务器),那么服务器会错误地建立连接,并一直等待客户端的数据。但客户端可能早已关闭或重新启动,根本不会发送数据。这会造成服务器资源的浪费。
- 三次握手可以避免:通过第三次握手,客户端再次确认了服务器的 SYN-ACK。如果服务器收到的 SYN 是失效的,那么客户端就不会发送第三次 ACK。服务器在接收到 SYN-ACK 后,如果没有收到客户端的 ACK 确认,就会知道这是一个失效的请求,从而关闭这个连接,避免了资源的浪费。
简而言之,三次握手确保了双方都确认了对方的收发能力,并且双方都为接下来的数据传输做好了准备。
TCP 是用来解决什么问题?
TCP 主要用来解决在不可靠的网络环境中,提供可靠的、面向连接的端到端数据传输服务的问题。
具体来说,TCP 解决了以下几个核心问题:
可靠性问题:
- 数据丢失:网络传输中数据包可能丢失。TCP 通过序列号 (Sequence Number) 和确认应答 (Acknowledgement) 机制,确保每个发送的数据包都能被接收方确认。如果一定时间内没有收到确认,发送方会重传该数据包。
- 数据乱序:数据包在网络中可能因路由不同而乱序到达。TCP 利用序列号对收到的数据进行排序和重组,保证交付给应用层的数据是严格按发送顺序的。
- 数据重复:重传机制可能导致数据包重复到达。TCP 也能通过序列号识别并丢弃重复的数据包。
- 数据损坏:数据包在传输过程中可能被损坏。TCP 使用校验和 (Checksum) 来检测数据完整性。如果校验和不匹配,数据包会被丢弃,并触发重传。
连接管理问题:
- 连接的建立:通过三次握手机制,在数据传输前双方确认彼此的收发能力,并协商初始序列号,为可靠传输奠定基础。
- 连接的释放:通过四次挥手机制,确保双方都完成了数据的发送,并安全地关闭连接,释放资源。
- 半关闭:允许一方发送完数据后关闭发送通道,但仍能接收数据。
流量控制问题:
- 避免拥塞接收方:发送方的发送速率可能远高于接收方的处理速率,导致接收方缓冲区溢出,数据丢失。TCP 通过滑动窗口 (Sliding Window) 机制,动态调整发送方可以发送的数据量,确保接收方有能力处理接收到的数据。接收方通过在确认报文中告知发送方其当前可用的接收窗口大小。
拥塞控制问题:
- 避免网络拥塞:当网络中存在大量数据时,可能导致路由器队列溢出,进而引起数据包丢失,降低网络吞吐量。TCP 通过一系列算法(如慢启动、拥塞避免、快速重传、快速恢复)来动态调整发送速率,感知网络拥塞,并主动降低发送速率,以缓解网络压力,防止“拥塞崩溃”。这是一种对全局网络资源的负责任行为。
数据分段和组装问题:
- TCP 会将应用层的大块数据分割成适合网络传输的报文段 (Segment),并在接收端将这些报文段重新组装成完整的应用层数据。
总结来说,TCP 解决了以下核心问题:
- 在复杂的、不可靠的互联网环境下,提供端到端的数据传输可靠性。
- 通过连接管理,确保通信的有序开始和结束。
- 通过流量控制,防止发送方淹没接收方。
- 通过拥塞控制,防止发送方加剧网络拥塞。
正是因为 TCP 解决了这些复杂的问题,才使得基于互联网的各种可靠应用(如网页浏览、文件传输、电子邮件等)成为可能。
说说 TCP 的四次挥手?
TCP 连接是 全双工 的,所以关闭时需要双方分别关闭发送通道,采用 四次挥手。
第一次挥手:
客户端主动发送
FIN
报文,表示自己已经没有数据要发送了,请求关闭连接。此时客户端进入FIN_WAIT_1
状态。第二次挥手:
服务端收到
FIN
后,回复一个ACK
确认报文,表示已经知道客户端要断开。此时服务端进入CLOSE_WAIT
状态,客户端进入FIN_WAIT_2
。第三次挥手:
服务端若数据发送完毕,也会发送
FIN
报文,表示可以断开连接。此时服务端进入LAST_ACK
状态。第四次挥手:
客户端收到
FIN
后,回复一个ACK
报文,进入TIME_WAIT
状态(等待 2MSL,确保服务端收到 ACK)。服务端收到 ACK 后进入
CLOSED
,客户端等待 2MSL 后也进入CLOSED
,连接彻底关闭。
关键点:
- 为什么需要四次?因为 TCP 是全双工,关闭需要双方分别通知。
- 为什么要有
TIME_WAIT
?防止最后一个 ACK 丢失,保证连接可靠释放。
TCP 是双向的,就像两个人打电话:
- 第一次:A 说“我没事了,可以挂了”。
- 第二次:B 回应“好的,我知道了”,但 B 可能还有话没说完。
- 第三次:B 说“我也说完了,可以挂了”。
- 第四次:A 回应“好的,那就挂吧”,并稍微等一会儿,确保 B 确实收到了,然后才彻底挂掉。
所以要四次,确保双方都彻底说完。
TCP 的粘包和拆包能说说吗?
TCP 是 面向字节流 的协议,没有消息边界,所以可能出现粘包和拆包:
粘包:多个小的数据包被 合并到一个 TCP 报文 里发送,接收方一次性读到多个数据。
原因:
- TCP 会根据缓存优化发送(Nagle 算法)。
- 应用层发送速度快于接收方处理速度,数据积累后一起发。
拆包:一个大的数据包被拆分成多个 TCP 报文。接收方可能一次只读到部分数据。
原因:
- TCP 发送数据时受 MSS(最大报文长度) 限制。
- 底层网络的 MTU 限制导致分片。
解决方法:
- 定长报文:每个消息规定固定长度,不足补齐。
- 分隔符协议:在消息末尾加特殊分隔符(如
\n
)。 - 长度前置:在数据包头部添加字段,表示消息长度。
- 更高级协议:使用像 HTTP、gRPC 这类已有的协议封装。
TCP 传输就像往水管里倒水,没有边界:
- 如果倒得太快,小份水可能会“挤”在一起流出来(粘包)。
- 如果一大桶水太多,可能被切成几段分别送(拆包)。
解决办法就是在水里加“标记”,比如加固定长度、加分隔符,或者在开头写清楚“我这桶水有多大”。这样接收方就能分清楚消息的边界。
说说 TCP 拥塞控制的步骤?
TCP 拥塞控制是防止过多数据注入网络导致拥塞,使用 拥塞窗口 cwnd 进行控制。
慢启动(Slow Start)
- 初始时 cwnd = 1 MSS。
- 每收到一个 ACK,cwnd 翻倍(指数增长)。
- 直到达到阈值(ssthresh)。
拥塞避免(Congestion Avoidance)
- cwnd >= ssthresh 时,进入拥塞避免。
- 每次 RTT,cwnd 线性 +1 MSS,避免增长过快。
快速重传(Fast Retransmit)
- 如果接收方收到失序数据,会发送 重复 ACK。
- 发送方连续收到 3 个重复 ACK,立即重传丢失的报文,不等超时。
快速恢复(Fast Recovery)
- 触发快速重传后:
- ssthresh = cwnd / 2。
- cwnd = ssthresh。
- 进入拥塞避免阶段(线性增长)。
- 这样避免了从头开始的慢启动。
- 触发快速重传后:
可以想象你开车上高速:
- 慢启动:刚上路时,先慢慢加速(窗口指数增长)。
- 拥塞避免:车多了,就稳着开,不要猛踩油门(窗口线性增长)。
- 快速重传:如果发现有个包丢了,不等交警提醒,自己马上补发。
- 快速恢复:撞车后不是回到起点,而是减速一半,稳住速度再跑。
这样 TCP 就能既跑得快,又不把“高速公路”堵死。
TCP/IP 四层模型是什么?
TCP/IP 四层模型就是应用层、传输层、网络层、网络接口层,对应 OSI 七层的合并版本。
应用层(Application Layer)
- 直接面向用户,提供各种应用服务。
- 典型协议:HTTP、FTP、SMTP、DNS。
传输层(Transport Layer)
- 负责端到端的通信,保证数据能完整、正确地到达目标进程。
- 典型协议:TCP(面向连接,可靠传输)、UDP(无连接,快速传输)。
网络层(Internet Layer)
- 负责寻址和路由选择,让数据包找到目标机器。
- 典型协议:IP、ICMP、ARP。
网络接口层(Network Access Layer / Link Layer)
- 负责物理传输,把比特流在物理网络上传输。
- 典型协议:以太网、WiFi、PPP。
Cookie、Session、Token 之间有什么区别?
这三个都是会话管理机制,区别主要体现在存储位置、安全性和适用场景。
Cookie
- 存在客户端(浏览器),由服务端下发。
- 每次请求时,浏览器会自动带上 Cookie。
- 缺点:容易被窃取、篡改,大小有限制。
- 适合存储无敏感信息(如用户偏好)。
Session
- 存在服务端,通常用内存、数据库或分布式缓存(Redis)存储。
- 客户端通过 SessionID(通常存在 Cookie 中) 关联服务端的会话数据。
- 安全性比 Cookie 高,但服务端需要维护状态,扩展性差。
- 适合传统 Web 应用。
Token(例如 JWT)
- 一种无状态认证方式。
- 服务端签发 Token(通常是加密后的字符串),客户端存储(LocalStorage/Cookie)。
- 每次请求客户端带上 Token,服务端只需验证签名即可,不用保存用户状态。
- 扩展性好,适合分布式系统、移动端、前后端分离项目。
从网络角度来看,用户从输入网址到网页显示,期间发生了什么?
DNS 解析
- 浏览器先查缓存,如果没有就向 DNS 服务器请求,把域名解析为 IP 地址。
建立 TCP 连接
- 浏览器和服务器通过 三次握手 建立 TCP 连接。
发起 HTTP 请求
- 浏览器发送 HTTP 请求报文(GET/POST 等),请求头里会带上 Cookie/Token。
服务器处理请求
- 服务端(例如 Nginx → 应用服务 → 数据库)处理业务逻辑,并生成响应。
服务器返回响应
- 返回 HTTP 响应报文,可能包含 HTML、CSS、JS、JSON 数据等。
浏览器解析渲染
- 解析 HTML → 构建 DOM 树。
- 解析 CSS → 构建 CSSOM 树。
- 合并为 Render Tree → 布局和绘制。
- 执行 JavaScript,可能再次发起请求(如 AJAX)。
页面显示
- 用户最终看到完整的网页。