面试题-网络协议

面试题-网络协议

网络模型

说一下OSI模型
  • 应用层,负责给应用程序提供统一的接口,HTTP、DNS;
  • 表示层,负责把数据转换成兼容另一个系统能识别的格式;
  • 会话层,负责建立、管理和终止表示层实体之间的通信会话;
  • 传输层,负责端到端的数据传输,TCP、UDP;
  • 网络层,负责数据的路由、转发、分片,IP;
  • 数据链路层,负责数据的封帧和差错检测,以及 MAC 寻址,交换机;
  • 物理层,负责在物理网络中传输数据帧;

OSI 模型是国际标准化组织定义的网络通信分层架构,共 7 层,从下到上依次为物理层、数据链路层、网络层、传输层、会话层、表示层、应用层,实现 "层间解耦、整体通信"。

最底层的物理层是网络通信的硬件基础,负责处理电信号、光信号等物理介质的传输,定义硬件接口(如 RJ45)、信号编码和传输速率,核心是将数据转为物理信号,不涉及逻辑处理。往上的数据链路层,负责相邻设备间的 "帧传输",封装 MAC 地址(源 / 目标)和校验位,通过 MAC 地址识别局域网设备,用 CRC 校验检测帧损坏并请求重传,交换机、网桥就工作在这一层,依赖以太网、PPP 等协议。

网络层是跨网络通信的核心,负责 "路由选择" 和 "IP 地址管理"------ 给数据封装 IP 地址,路由器通过路由表计算最优路径,将数据从源网络转发到目标网络,解决不同局域网间的通信问题,核心协议有 IP(IPv4/IPv6)、ICMP(ping 命令依赖)。传输层则聚焦 "端到端的进程级通信",通过端口号定位应用程序,提供两种传输方式:TCP 协议(可靠,三次握手、重传机制,适合文件传输)和 UDP 协议(高效,无连接,适合视频通话),实现数据的有序、不丢失或低延迟传输。

上层的会话层、表示层、应用层偏向应用逻辑:会话层负责建立、维护通信会话(如身份验证、超时控制);表示层处理数据格式转换(如 JSON/XML)、加密(如 TLS)和压缩,确保接收方解析;应用层是用户与网络的接口,直接提供应用服务,常见协议如 HTTP(网页)、FTP(文件传输)、DNS(域名解析),日常使用的浏览器、邮件客户端都依赖这一层协议。

说一下TCP/IP模型

TCP/IP 模型是互联网实际遵循的分层架构,更贴近应用,通常分 4 层(也有 5 层划分,拆分网络接口层),从下到上为网络接口层、网络层、传输层、应用层,是互联网通信的核心基础。

最底层的网络接口层对应 OSI 的物理层 + 数据链路层,负责物理介质传输和局域网帧交互,不定义具体协议,依赖实际硬件(如网卡)和链路协议(如以太网、WiFi),比如电脑通过以太网协议将数据封装成帧,在局域网内传输。往上的网络层是跨网通信的核心,核心功能是 "IP 地址分配" 和 "路由转发"------ 给数据封装 IP 地址(源 / 目标),通过 IP 协议确定逻辑路径,路由器通过路由表将数据从源网络转发到目标网络,辅助协议有 ICMP(ping 诊断)、ARP(IP 查 MAC)。

传输层与 OSI 传输层功能一致,负责 "端到端的进程级通信":通过端口号定位应用程序,提供 TCP(可靠传输,三次握手、重传,适合网页、文件)和 UDP(高效无连接,适合视频、DNS)两种服务,用 "IP + 端口" 实现不同设备上应用的通信。最上层的应用层对应 OSI 的会话层 + 表示层 + 应用层,直接面向用户应用,提供具体网络服务,常见协议如 HTTP(网页访问)、HTTPS(安全网页)、FTP(文件传输)、SMTP(邮件)、DNS(域名转 IP),日常使用的浏览器、邮件客户端本质是通过应用层协议与服务器交互。

TCP、IP分别在哪一层

在 TCP/IP 模型中,IP 协议工作在网络层TCP 协议工作在传输层;对应 OSI 模型,两者层级归属完全一致 ------IP 仍在网络层,TCP 仍在传输层。

应用层

应用层有哪些协议

应用层协议是直接面向用户业务的网络协议,负责定义应用程序间通信的格式与规则,常见的核心协议包括:HTTP/HTTPS(超文本传输协议 / 安全版),前者用于网页访问、API 接口交互(如浏览器加载网页、App 调用后端接口),后者通过 TLS 加密保障传输安全,是电商、支付等场景的标配;FTP(文件传输协议),用于客户端与服务器间的文件上传下载(如开发者向服务器传代码包、用户下载大文件);邮件相关协议,SMTP(简单邮件传输协议)负责发送邮件,POP3/IMAP(邮局协议 / 互联网消息访问协议)负责接收邮件(如 Outlook、网易邮箱的收发功能);DNS(域名系统协议),将易记的域名(如www.baidu.com)转换为机器识别的 IP 地址;SSH(安全外壳协议),用于远程登录服务器并执行命令(如开发者通过 SSH 管理云服务器),替代了不安全的 Telnet 协议;

HTTP报文有哪些内容

HTTP 报文分为请求报文响应报文 ,两者结构相似但核心字段不同,均由 "头部 + 空行 + 体" 三部分组成(部分场景无体)。

请求报文用于客户端向服务器发送请求,核心内容包括:第一行 "请求行",包含请求方法(如 GET、POST)、请求 URL、HTTP 版本,明确 "做什么、操作哪个资源、用哪个协议版本";随后是 "请求头",以键值对形式存在(如 Host: www.xxx.com指定目标服务器域名,User-Agent: Chrome/112.0... 说明客户端浏览器信息,Cookie: sessionid=xxx 携带用户会话信息),用于传递请求的附加信息;请求头后是 "空行",作为头与体的分隔符;最后是 "请求体",仅在 POST、PUT 等方法中存在,用于携带业务数据(如表单数据、JSON 格式的用户信息),GET 方法的参数通常拼在 URL 中,无请求体。

响应报文用于服务器向客户端返回结果,核心内容包括:第一行 "状态行",包含 HTTP 版本、状态码(如 200、404)、状态短语(如 OK、Not Found);随后是 "响应头",同样是键值对(如 Content-Type: application/json 指定响应体格式,Server: Nginx 说明服务器软件,Set-Cookie: token=xxx 向客户端写入 Cookie);响应头后是 "空行";最后是 "响应体",返回客户端需要的实际数据(如 HTML 网页代码、JSON 格式的接口结果、图片二进制数据),HEAD 方法的响应无体。

HTTP的常用状态码

1xx(信息类):仅 100 Continue 较常见,表示服务器已收到请求头,客户端可继续发送请求体(如 POST 大文件时的预处理);

2xx(成功类):200 OK 表示请求成功(如 GET 获取数据、POST 提交成功),204 No Content 表示请求成功但无响应体(如 DELETE 删除资源后无需返回数据);

3xx(重定向类):301 Moved Permanently(永久重定向,如域名更换后旧地址跳新地址),302 Found(临时重定向,如临时维护时跳公告页),304 Not Modified(缓存命中,服务器告知客户端 "本地缓存未过期,可直接使用");

4xx(客户端错误类):400 Bad Request(请求参数错误,如格式非法),401 Unauthorized(未认证,如未登录访问需要权限的接口),403 Forbidden(已认证但无权限,如普通用户访问管理员接口),404 Not Found(请求的资源不存在,如 URL 输错),405 Method Not Allowed(请求方法不支持,如用 POST 访问仅允许 GET 的接口);

5xx(服务器错误类):500 Internal Server Error(服务器内部未知错误,如代码 bug),502 Bad Gateway(网关收到上游服务器无效响应,如 Nginx 背后的 Tomcat 崩溃),503 Service Unavailable(服务器暂时不可用,如高峰期过载、维护中),504 Gateway Timeout(网关等待上游服务器响应超时,如上游接口处理耗时过长)。

HTTP返回状态301和302分别是什么

301 是 "Moved Permanently(永久重定向)",表示请求的资源已 "永久迁移" 到新 URL,浏览器会缓存这个重定向关系 ------ 首次收到 301 后,后续再访问原 URL 时,会直接跳转到新 URL,无需再向服务器发起请求;对 SEO 而言,搜索引擎会将原 URL 的权重转移到新 URL,适合域名更换、资源永久迁移的场景(如旧域名www.old.com永久跳转到www.new.com)。

302 是 "Found(临时重定向)",表示资源 "暂时" 在新 URL,浏览器不会缓存重定向关系 ------ 每次访问原 URL,都会先向服务器发起请求,再根据服务器响应跳转到新 URL;对 SEO 而言,搜索引擎不会转移原 URL 的权重,仍会收录原 URL,适合临时场景(如服务器维护时,将所有请求临时跳转到维护公告页,维护结束后恢复原 URL)。

HTTP返回状态502和504的区别

502 是 "Bad Gateway(网关错误)",表示网关(如 Nginx)已成功连接到上游服务器(如 Tomcat、后端 API 服务),但上游服务器返回了 "无效响应"(如上游服务崩溃导致返回乱码、连接突然断开),网关无法将无效响应转化为客户端能理解的 HTTP 报文,因此返回 502;常见场景如上游 Tomcat 进程挂掉、代码 bug 导致上游服务抛出异常、网络波动导致上游响应中断。

504 是 "Gateway Timeout(网关超时)",表示网关已成功连接到上游服务器,但等待上游服务器返回响应的时间超过了网关的超时阈值(如 Nginx 配置的 proxy_connect_timeout),网关未收到任何有效响应,因此返回 504;常见场景如上游接口处理逻辑复杂(如大数据量计算)耗时过长、上游服务器负载过高(CPU / 内存满)导致处理缓慢、网关与上游服务器间网络拥堵。

HTTP请求类型有哪些

GET:用于 "获取" 资源(如查询用户信息、加载网页),参数通常拼在 URL 中(如 /api/user?id=1),无请求体,请求结果可缓存,适合无副作用的查询操作;

POST:用于 "提交" 数据(如创建订单、提交表单),参数放在请求体中(可传 JSON、表单数据),请求结果不可缓存,多次提交可能产生不同结果(如重复创建订单);

PUT:用于 "全量更新" 资源(如将用户年龄从 20 改为 25,需传完整用户信息),请求体携带更新后的完整数据,多次执行结果一致(幂等);

DELETE:用于 "删除" 资源(如删除一条订单记录),无请求体或仅传资源 ID,多次执行结果一致(幂等);

PATCH:用于 "部分更新" 资源(如仅更新用户手机号,无需传完整信息),请求体携带部分字段,相比 PUT 更灵活;

HEAD:与 GET 功能一致,仅返回响应头,无响应体(如仅判断资源是否存在,无需获取具体数据);

OPTIONS:用于 "获取服务器支持的请求方法"(如查询 /api/user 接口允许 GET/POST);

HTTP哪些请求方式是幂等的

幂等性是指 "多次执行同一请求,最终结果与执行一次完全一致,不会产生额外副作用"(如不会重复创建数据、重复扣减库存),HTTP 中满足幂等性的请求方式包括:

GET:仅用于获取资源,无论执行多少次,都不会改变服务器数据(如多次查询同一用户信息,结果始终相同),无副作用,天然幂等;

PUT:用于更新资源,即使多次执行,最终结果也与一次执行一致(如 "将用户年龄改为 25",第一次执行后年龄变为 25,后续再执行,年龄仍为 25,不会变化),无额外副作用;

DELETE:用于删除资源,第一次执行会删除资源,后续再执行时,服务器虽提示 "资源不存在",但最终结果(资源已删除)与一次执行一致,不会产生新副作用;

HEAD:与 GET 逻辑一致,仅返回响应头,不处理或改变服务器数据,幂等;

OPTIONS:仅用于查询服务器支持的方法,不改变服务器状态,幂等。

非幂等的请求方式主要是 POST(多次提交会产生额外副作用,如多次 POST 创建订单,会生成多个订单记录);PATCH 需根据业务逻辑判断 ------ 若用于 "部分更新固定值"(如将手机号改为 138xxx),则幂等;若用于 "增量更新"(如 "将积分增加 10"),则非幂等(多次执行积分会持续增加)。

HTTP的长连接了解吗

HTTP 长连接是为解决 "短连接频繁建立 / 断开的性能开销" 设计的连接复用机制,核心通过Connection: keep-alive头部实现。在 HTTP/1.0 中默认是短连接 ------ 每次请求都要新建 TCP 连接(三次握手),请求完成后立即断开(四次挥手),若客户端需多次请求资源(如加载网页中的图片、CSS),会频繁建连,产生大量网络开销。而 HTTP/1.1 将长连接设为默认,客户端发起请求时,会在请求头中携带Connection: keep-alive(若不携带则默认启用),服务器响应时也会返回该头部,标识 "本次 TCP 连接不立即断开,可复用"。

复用期间,客户端可通过同一 TCP 连接连续发送多个 HTTP 请求,无需重复三次握手,大幅减少网络延迟;同时,长连接会设置 "超时时间"(如服务器配置keepalive_timeout 60s)和 "最大请求数"(如keepalive_requests 100),避免连接长期闲置占用资源 ------ 若超时无新请求,或已处理的请求数达上限,服务器会主动断开连接。不过,长连接虽提升性能,但需注意 "队头阻塞" 问题:同一连接中,前一个请求未完成时,后续请求需排队等待,HTTP/2 通过多路复用以解决该问题,但 HTTP/1.1 的长连接仍依赖连接复用缓解基础开销。

HTTP和HTTPS的默认端口

HTTP(超文本传输协议)的默认端口是80 ,HTTPS(基于 TLS/SSL 的安全超文本传输协议)的默认端口是443 。客户端发起请求时,若 URL 未指定端口(如http://www.baidu.comhttps://www.baidu.com),会自动使用对应默认端口建立连接 ------ 例如,访问http://xxx.com时,客户端会默认连接服务器的 80 端口;访问https://xxx.com时,默认连接 443 端口。

HTTP/1.1是怎么对请求进行拆包的

HTTP/1.1 的请求拆包,核心是解决 "TCP 面向字节流的粘包 / 拆包问题"------TCP 传输时会将数据拆分为多个数据包,或合并多个小数据包,HTTP/1.1 需通过明确的 "边界标识",让服务器能从 TCP 流中准确解析出单个 HTTP 请求,主要依赖以下两种机制:

一是基于 Content-Length 的长度标识 :当请求有 body(如 POST、PUT 请求)时,客户端会在请求头中添加Content-Length: N(N 为 body 的字节数),服务器接收数据时,先解析请求头获取 Content-Length,再从后续 TCP 流中读取 N 字节的数据作为该请求的 body,读取完成即标志一个请求解析结束。这种方式适合 body 长度可提前确定的场景(如表单提交、固定大小的 JSON 数据)。

二是基于 Transfer-Encoding: chunked 的分块传输 :若请求 body 长度无法提前确定(如动态生成的大文件、流式数据),客户端会在请求头中设置Transfer-Encoding: chunked,此时 body 会被拆分为多个 "数据块"------ 每个数据块开头用十六进制数字标识该块的字节数, followed by \r\n,再跟上数据块内容;所有数据块传输完成后,用一个 "长度为 0 的块"(0\r\n\r\n)标识结束。服务器接收时,会按 "读取块长度→读取对应字节数据" 的流程逐块解析,直到遇到 0 长度块,确认请求解析完成。

说一下HTTP断点续传

HTTP 断点续传是针对 "大文件下载中断后重新续传" 的优化机制,核心通过Range请求头和206 Partial Content响应状态码实现,避免中断后重新下载整个文件,节省带宽和时间。

其工作流程如下:首先,客户端首次下载文件时,服务器会在响应头中返回Accept-Ranges: bytes,标识 "支持断点续传",同时返回Content-Length: 1024000告知客户端文件总字节数。若下载中断(如网络断开、客户端关闭),客户端会记录已下载的字节范围(如已下载前 200000 字节,即0-199999);重新下载时,客户端在请求头中添加Range: bytes=200000-(表示 "请求从第 200000 字节开始到文件末尾的数据",也可指定具体范围如200000-499999)。

服务器收到Range请求后,会先校验请求的范围是否合法(如是否超过文件总长度):若合法,返回206 Partial Content状态码,同时在响应头中添加Content-Range: bytes 200000-999999/1000000(明确当前传输的字节范围和文件总大小),并仅传输该范围的数据;若范围不合法(如Range: bytes=2000000-超过文件总长度),则返回416 Requested Range Not Satisfiable,告知客户端请求范围无效。

客户端接收 206 响应后,将传输的部分数据追加到已下载的文件中,直至整个文件下载完成。常见的下载工具(如浏览器、迅雷)、视频播放的 "进度条拖动"(跳转到指定时间点播放),均依赖断点续传机制。

HTTP为什么不安全

一是明文传输导致数据窃听:HTTP 的所有数据(包括请求参数、Cookie、用户账号密码等敏感信息)均以明文形式在网络中传输,未经过任何加密处理。若数据经过公共网络(如咖啡厅 WiFi、运营商网络),攻击者可通过抓包工具(如 Wireshark)直接捕获并读取传输内容,例如用户在 HTTP 网站登录时,账号密码可能被直接窃取。

二是无身份验证导致服务器冒充 :HTTP 协议未提供 "验证服务器身份" 的机制,客户端无法确认自己连接的是否为真实目标服务器。攻击者可通过 "DNS 劫持" 或 "中间人攻击",将客户端的请求导向伪造的服务器 ------ 例如,用户想访问http://www.bank.com,却被劫持到攻击者搭建的仿冒银行网站,输入的银行卡信息会被攻击者获取。

三是无数据完整性校验导致数据篡改:HTTP 传输的数据未附加 "完整性校验信息",攻击者可在数据传输过程中拦截并修改内容,且客户端无法察觉。例如,用户在 HTTP 电商网站下单时,攻击者可拦截请求,将 "商品价格 100 元" 改为 "1 元",或修改收货地址,导致商家和用户的损失。

HTTP和HTTPS的区别

协议基础与安全性看:HTTP 是 "超文本传输协议",基于 TCP 直接传输,数据明文且无身份验证、完整性校验,安全性差;HTTPS 是 "HTTP over TLS/SSL",在 HTTP 和 TCP 之间增加了 TLS/SSL 加密层,通过对称加密传输数据、非对称加密交换密钥、CA 证书验证服务器身份,能防止窃听、篡改、冒充,安全性高。

非对称加密:加密和解密用 "两把不同的密钥"

对称加密:加密和解密用 "同一把密钥"

性能开销看:HTTP 无需加密解密过程,建立连接仅需 TCP 三次握手,性能开销低;HTTPS 需额外进行 TLS 握手(交换密钥、验证证书),且传输数据时需加密解密,会产生一定性能开销(通常增加 10%-30% 延迟),但可通过 TLS 会话复用、硬件加速等优化。

证书要求看:HTTP 无需任何证书,服务器可直接部署;HTTPS 需向 CA(如 Let's Encrypt、Symantec)申请数字证书,证书用于验证服务器身份,若使用自签证书,客户端会提示 "不安全" 并拒绝连接。

适用场景看:HTTP 适合静态资源(如公开的图片、文档)或无敏感信息的场景;HTTPS 适合涉及敏感信息的场景(如登录、支付、电商、政务),是当前互联网的主流协议(浏览器对 HTTP 网站会标注 "不安全")。

HTTPS为什么能保证安全性的,如何防止攻击的

HTTPS 的安全性依赖TLS/SSL 协议的三大核心机制 :数据加密、身份验证、数据完整性校验,分别对应防御 "窃听、冒充、篡改" 三类攻击,具体如下:

一是数据加密:防止窃听:TLS 采用 "非对称加密 + 对称加密" 的混合加密方案 ------ 握手阶段用非对称加密(服务器公钥加密、私钥解密)交换 "预主密钥",避免密钥在传输中被窃取;握手完成后,双方用预主密钥生成 "对称密钥",后续所有 HTTP 数据均用对称密钥加密传输。即使攻击者捕获传输数据,因无对称密钥,也无法解密内容,从而防止数据窃听。

二是身份验证:防止服务器冒充:TLS 通过 "CA 数字证书" 验证服务器身份 ------ 服务器需向权威 CA 申请证书,证书中包含服务器公钥、域名、CA 签名等信息;客户端发起 HTTPS 请求时,服务器会发送证书给客户端,客户端会验证证书的合法性(如检查 CA 签名是否有效、证书是否过期、证书中的域名是否与请求域名一致)。若证书合法,说明服务器是真实的;若证书非法(如自签证书、篡改证书),客户端会提示 "不安全" 并拒绝连接,从而防止攻击者冒充目标服务器。

三是数据完整性校验:防止数据篡改:TLS 在传输数据时,会对每个数据块计算 "消息认证码(MAC)",并将 MAC 附加在数据后;客户端接收数据时,会重新计算 MAC 并与接收的 MAC 对比,若不一致,说明数据在传输中被篡改,客户端会丢弃数据并断开连接。这种机制确保数据传输过程中未被修改,防止攻击者篡改请求参数(如价格、账号)或响应内容。

HTTPS协议TLS握手过程
  1. 客户端发送 Client Hello:客户端发起握手,向服务器发送包含三部分信息的数据包:支持的 TLS 版本(如 TLS 1.2)、支持的加密套件列表(如 ECDHE-RSA-AES256-GCM-SHA384,包含密钥交换、对称加密、哈希算法)、一个随机数(Client Random),用于后续生成对称密钥。
  2. 服务器发送 Server Hello:服务器从客户端的请求中选择匹配的配置,返回数据包:确认的 TLS 版本、选定的加密套件(如上述 ECDHE 套件)、一个随机数(Server Random),同样用于生成对称密钥;同时,服务器会关闭客户端不支持的配置,确保双方加密规则一致。
  3. 服务器发送证书与密钥交换信息:服务器继续发送两部分内容:一是 CA 签发的数字证书(包含服务器公钥、域名、CA 签名等),供客户端验证身份;二是 "密钥交换参数"(如 ECDHE 算法的公钥参数 Server Params),用于后续生成预主密钥(Pre-Master Secret)。
  4. 客户端验证证书与生成预主密钥:客户端接收证书后,执行证书验证(检查 CA 签名、有效期、域名匹配),若验证失败,提示 "不安全" 并终止握手;若验证成功,客户端用服务器的公钥(从证书中提取)加密 "预主密钥"(结合 Client Params 和 Server Params 生成),生成 "Encrypted Pre-Master Secret",发送给服务器。
  5. 服务器解密获取预主密钥:服务器用自己的私钥解密 "Encrypted Pre-Master Secret",得到预主密钥;至此,客户端和服务器均拥有三个核心参数:Client Random、Server Random、Pre-Master Secret。
  6. 双方生成对称密钥:客户端和服务器分别使用相同的算法(如 PRF 算法),结合 Client Random、Server Random、Pre-Master Secret,生成完全相同的 "对称密钥"(包含会话密钥、MAC 密钥),后续 HTTP 数据均用该对称密钥加密传输。
  7. 握手完成确认:客户端生成 "Finished" 消息(用对称密钥加密,包含前序所有握手消息的哈希值),发送给服务器;服务器接收后,用对称密钥解密并验证哈希值(确认握手过程无篡改),验证通过后,同样生成 "Finished" 消息发送给客户端;客户端验证服务器的 Finished 消息通过后,TLS 握手完成,后续客户端与服务器通过对称密钥传输 HTTP 数据。
HTTP/1.1和HTTP/2的区别

传输方式与并发能力看,HTTP/1.1 基于 "文本帧" 传输,且同一 TCP 长连接中,多个请求需按顺序排队("队头阻塞")------ 前一个请求未完成时,后续请求只能等待,若前一个请求耗时久(如大文件下载),会阻塞所有后续请求,只能通过 "建立多 TCP 连接"(通常浏览器限制 6-8 个 / 域名)缓解,仍有资源浪费。而 HTTP/2 采用 "二进制帧" 传输,将每个 HTTP 请求 / 响应拆分为独立的 "二进制帧",并为每个帧标记 "流 ID"(同一请求的帧对应同一流 ID);同一 TCP 连接中可同时传输多个流的帧("多路复用"),帧的传输无需按顺序,接收方通过流 ID 重组数据,彻底解决了队头阻塞问题,单个 TCP 连接即可支撑数千个并发请求,大幅减少连接开销。

头部优化看,HTTP/1.1 的请求头以文本形式传输,且每次请求都会携带大量重复头部(如 User-Agent、Cookie、Host),导致头部冗余(有时头部大小甚至超过请求体),浪费带宽。HTTP/2 引入 "HPACK 头部压缩算法":客户端和服务器维护一张 "静态字典"(预定义常见头部,如 Host、Method)和 "动态字典"(记录本次连接中已传输的自定义头部,如 Cookie),传输头部时仅发送 "字典索引" 或 "差异数据",无需重复发送完整头部,头部体积可压缩至原来的 1/10 甚至更小,显著降低带宽消耗。

服务器推送看,HTTP/1.1 是 "客户端主动请求 - 服务器被动响应" 模式,客户端需先请求 HTML,解析后再请求 CSS、JS 等依赖资源,存在 "请求延迟"。HTTP/2 支持 "服务器推送"------ 服务器解析客户端请求(如请求 HTML)时,可预判客户端后续需要的资源(如关联的 CSS、JS),主动将这些资源推送到客户端缓存,无需客户端额外发起请求,减少页面加载时间(如浏览器打开网页时,无需等待解析 HTML 后再请求 CSS,可直接使用服务器推送的 CSS)。

此外,HTTP/2 还支持 "流量控制"(基于流的滑动窗口,避免单个流占用过多带宽)和 "优先级设置"(客户端可给请求标记优先级,如 HTML 优先于图片,服务器按优先级处理帧),进一步优化资源加载顺序;而 HTTP/1.1 无这些能力,只能被动按请求顺序处理。

HTTP建立TCP连接后,什么情况会中段

HTTP 建立 TCP 连接后,中断多源于通信链路、两端设备或中间节点异常,核心是双向通信无法维持。网络层面,若客户端断网或路由器等中间节点故障,会直接切断传输路径;若数据包丢失过多,TCP 重传多次失败后,会判定连接无效并主动关闭。

服务器层面,常见于连接空闲超时 ------ 服务器对长连接配置了 keep-alive 超时(如 Nginx 默认 60 秒),长时间无数据传输会主动断连释放资源;若服务进程崩溃、服务器重启,也会强制终止所有已建立的连接。

客户端层面,用户关闭浏览器、退出 App 时,客户端会主动发起断连;若客户端设置了请求超时(如 5 秒),服务器响应慢超阈值,客户端会主动终止连接避免等待。

中间件层面,网关或代理(如 Nginx)若配置了后端超时,上游服务器处理耗时过长会断连,同时向客户端返回 504 错误;

HTTP、SOCKET、TCP的区别

协议层级与定位看:TCP(传输控制协议)属于 OSI 模型的传输层,核心作用是 "在两个设备间建立可靠的、面向连接的字节流传输"------ 通过三次握手建连、四次挥手断连、滑动窗口流量控制、重传机制,确保数据有序、不丢失、不重复,为上层应用提供 "端到端的可靠传输能力",不关心数据的具体内容(仅传输字节流)。SOCKET(套接字)并非协议,而是 "操作系统提供的、用于网络编程的接口(API)",本质是 "TCP/UDP 协议的编程入口"------ 应用程序无法直接操作 TCP 协议,需通过 SOCKET 接口(如 C 语言的 socket ()、connect ()、send () 函数)创建连接、发送 / 接收数据,SOCKET 屏蔽了 TCP/UDP 的底层细节,让开发者能快速实现网络通信(可基于 TCP 创建可靠连接,也可基于 UDP 创建不可靠连接)。HTTP(超文本传输协议)属于应用层协议,基于 TCP 协议实现,核心作用是 "定义客户端与服务器间的请求 / 响应格式与交互规则"------ 规定了请求方法(GET/POST)、状态码、报文结构(请求行 / 响应行、头部、体),专注于 "Web 场景的资源传输"(如网页、API 数据),本质是 "在 TCP 可靠传输的基础上,封装了应用层的业务逻辑规则"。

功能与使用场景看:TCP 的功能是 "可靠传输字节流",不包含任何应用层逻辑,适合所有需要可靠传输的场景(如文件传输、即时通信、数据库连接),但需上层应用自行定义数据格式(如 MySQL 的协议、Redis 的 RESP 协议)。SOCKET 的功能是 "提供编程接口",本身不实现通信逻辑,而是让应用能调用 TCP/UDP 的能力,开发者基于 SOCKET 可开发各种网络应用(如客户端的聊天软件、服务器的 TCP 服务),需自行处理数据的封装与解析。HTTP 的功能是 "标准化 Web 通信",内置了请求 / 响应逻辑,无需开发者定义数据格式,适合 Web 场景(如浏览器访问网页、App 调用后端 API),但灵活性低 ------ 仅支持特定的交互模式(请求 - 响应),无法实现 "服务器主动推数据"(需依赖 WebSocket,而 WebSocket 也基于 TCP,通过 SOCKET 实现)。

依赖关系 看:HTTP 依赖 TCP(必须先建立 TCP 连接才能传输 HTTP 数据),TCP 依赖操作系统的网络栈实现,而 SOCKET 是连接 "应用程序" 与 "TCP/UDP 协议" 的桥梁 ------ 应用程序通过 SOCKET 调用 TCP 协议,建立连接后传输 HTTP 数据。简单来说:SOCKET 接口 → TCP 协议 → HTTP 协议(应用层规则),三者从底层到上层,共同支撑 Web 通信。

了解DNS吗

DNS(域名系统)是互联网的 "地址翻译官",作用是将人类易记的域名(如www.baidu.com)转换为机器可识别的 IP 地址(如 14.215.177.38)。互联网中设备间通信依赖 IP 地址,但域名更易记忆,DNS 便解决了 "记 IP 难" 的问题。它采用层级化结构,从根域名服务器(全球共 13 组)、顶级域服务器(如.com、.cn)、二级域服务器(如baidu.com)到权威域名服务器,逐层解析域名;同时支持缓存机制,客户端、路由器、ISP 服务器会缓存解析结果,减少重复查询,提升解析速度,是互联网访问的基础支撑。

DNS域名的工作流程

当用户在浏览器输入域名(如www.baidu.com)后,DNS 解析流程大致如下:首先,客户端会先查询本地缓存(如浏览器缓存、操作系统缓存),若之前解析过该域名且缓存未过期,直接获取 IP 地址;若本地缓存无结果,查询路由器缓存,命中则返回 IP。若路由器缓存也无结果,客户端会访问 本地 DNS 服务器(网络服务商的 DNS 服务器(如电信、联通的 DNS)),多数常见域名的解析结果会在此缓存,命中后返回 IP;若仍未命中,本地 DNS 服务器会向根域名服务器发起请求,根服务器不直接返回 IP,而是告知 ".com 顶级域服务器的地址"。本地 DNS 接着访问.com 顶级域服务器,顶级域服务器同样不返回 IP,而是提供 "baidu.com二级域服务器的地址";本地 DNS 服务器 再访问baidu.com的权威域名服务器(该域名的实际管理服务器),权威服务器存储着www.baidu.com对应的 IP 地址,会将 IP 返回给本地 DNS 服务器。最后,本地 DNS 服务器 将 IP 地址返回给客户端,同时缓存该解析结果,客户端通过 IP 地址与目标服务器建立连接,完成域名解析;后续若再访问同一域名,可直接从缓存获取 IP,提升效率。

DNS的默认端口

默认端口:53

DNS底层是TCP还是UDP为什么

普通域名查询优先用 UDP,因为 UDP 是无连接协议,无需建立 TCP 那样的三次握手,传输开销小、速度快,而 DNS 查询通常是单次请求 - 响应,数据量小(一般不超过 512 字节),UDP 完全能满足需求,能快速返回解析结果,提升用户访问体验。

但在两种场景下会改用 TCP:一是 "区域传输",主 DNS 服务器向从 DNS 服务器同步解析记录时,数据量较大且需确保完整传输,TCP 的可靠传输(重传、校验)能避免数据丢失或损坏;二是 "响应数据超量",若解析结果超过 UDP 的 512 字节限制(如返回多个 IP 或复杂记录),UDP 无法完整传输,会改用 TCP 分段传输,确保解析结果准确。

HTTP是不是无状态的

HTTP 是无状态协议。"无状态" 指的是服务器不会保留客户端的历史请求信息,每次 HTTP 请求都是独立的 ------ 比如客户端第一次向服务器发送 "登录请求" 并成功登录后,第二次发送 "查询个人信息请求" 时,服务器无法通过 HTTP 协议本身识别出 "这是之前登录过的同一个客户端",需要额外的机制(如 Cookie、Session)才能关联两次请求。这种无状态设计让 HTTP 协议高效,服务器无需存储客户端状态,能轻松处理大量并发请求,但也导致无法直接维持用户会话,需依赖外部手段补充。

携带Cookie的HTTP的请求是有状态还是无状态的?Cookie是HTTP协议簇的一部分,那为什么还说HTTP是无状态的?

携带 Cookie 的 HTTP 请求,本质上仍属于无状态请求;Cookie 是 HTTP 协议簇的一部分,但它不是 HTTP 协议本身的状态。

具体来说,HTTP 协议的 "无状态" 是指协议核心没有内置 "存储客户端状态" 的机制 ------ 服务器不会主动记住客户端,每次请求的识别依赖于客户端主动携带的 Cookie(Cookie 中存储着服务器之前分配的标识,如 SessionID)。服务器通过 Cookie 识别客户端,看似 "有状态",但这种状态是客户端主动传递的,而非服务器通过 HTTP 协议本身保留的;若客户端不携带 Cookie,服务器仍无法识别客户端,协议本身的无状态属性并未改变。

Cookie、Session、Token的区别

Cookie 存储在客户端(浏览器或 App 的本地存储),数据由服务器生成后发送给客户端,每次 HTTP 请求会自动携带,安全性较低(可被客户端篡改或窃取),适合存储少量非敏感信息(如用户偏好)依赖 HTTP 协议,跨域时受浏览器同源策略限制。

Session 存储在服务器(如Web服务器Tomcat进程的JVM堆内存、数据库、Redis),服务器为每个客户端生成唯一的 SessionID,SessionID 通常通过 Cookie 传递给客户端;客户端后续请求携带 SessionID,服务器通过 SessionID 找到对应的 Session 数据,安全性较高(数据不在客户端存储),但会占用服务器资源,并发量高时可能增加服务器压力,且跨域时因 Cookie 限制,需额外处理(如 URL 重写)。

Token 是服务器生成的字符串(如 JWT 令牌),存储在客户端Cookie 或 localStorage,若存在localStorage中,客户端请求时在请求头(如 Authorization)中携带 Token,服务器通过解密 Token 验证身份,无需在服务器存储状态,减轻服务器压力;安全性中等(Token 可被窃取,但加密后难篡改),支持跨域(不依赖 Cookie),适合前后端分离、多端(Web、App)共用的场景。

如果客户端禁止Cookie,Session还能用吗

默认情况下禁用 Cookie 后,Session 是无法正常使用的,因为大多数 Web 服务器都是依赖于 Cookie 来传递 Session 的会话 ID 的。

若 Cookie 被禁止,可改用两种方案:一是 URL 重写,将 SessionID 拼在 URL 的查询参数中(如http://xxx.com/page?jsessionid=123456),服务器从 URL 中提取 SessionID 找到对应 Session;二是表单隐藏域,在表单中添加隐藏字段(如),提交表单时将 SessionID 传递给服务器。

但这两种方案有明显缺点:URL 重写会暴露 SessionID(易被窃取),且 URL 长度有限制,还不支持 GET 以外的请求方法;表单隐藏域仅适用于表单提交场景,无法覆盖所有请求(如链接跳转)。因此,Cookie 是传递 SessionID 的首选方式,禁止 Cookie 后虽能使用 Session,但体验和安全性会下降。

JWT令牌与传统的cookie、session的优势是什么

JWT 相比传统 Cookie、Session,核心优势集中在分布式适配、服务器压力、跨端兼容性三个维度。从分布式架构来看,Session 依赖服务器存储(如内存、数据库),分布式部署时需额外实现 Session 共享(如 Redis 集群),否则不同节点无法识别同一客户端;而 JWT 是 "无状态" 令牌,服务器无需存储任何会话信息,仅通过解析令牌即可验证身份,天然适配微服务、多节点部署,减少了分布式环境下的会话同步成本。

从服务器压力来看,Session 会占用服务器资源(尤其是高并发场景下,大量 Session 会消耗内存),且需定期清理过期 Session;JWT 的验证过程仅依赖本地计算(解密、验签),无需查询存储,大幅降低服务器的 IO 和内存开销,更适合高并发场景。

从跨端兼容性来看,Cookie 依赖浏览器环境,且受同源策略限制,在 App、小程序等非浏览器场景中适配复杂;JWT 可通过请求头(如 Authorization: Bearer Token)传输,不依赖特定客户端环境,支持 Web、App多端实现,同时规避了 Cookie 的跨域限制,更适合前后端分离或多端统一认证的架构。此外,JWT 支持自定义 Payload(如用户角色、权限),可直接携带业务信息,减少了服务器查询数据库的次数,进一步提升效率。

JWT令牌有哪些字段

JWT 令牌由Header(头部)、Payload(载荷)、Signature(签名) 三部分组成,三部分用 "." 连接,整体为 Base64Url 编码的字符串(非加密,可解码)。

Header 部分用于声明令牌的基础信息,通常包含两个字段:alg(加密算法,如 HS256(HMAC SHA256)、RS256(RSA SHA256))和typ(令牌类型,固定为 "JWT"),示例:{"alg":"HS256","typ":"JWT"},编码后作为令牌第一部分。

Payload 部分是令牌的核心,用于携带 "声明信息",分为标准声明和自定义声明。标准声明是 JWT 规范定义的可选字段,如iss(令牌签发者)、exp(令牌过期时间,Unix 时间戳)、sub(令牌主题,通常为用户 ID)、iat(令牌签发时间);自定义声明由开发者根据业务需求添加,如role(用户角色)、permissions(用户权限),示例:{"sub":"123456","name":"张三","role":"user","exp":1717248000},编码后作为令牌第二部分(需注意:Payload 仅为 Base64Url 编码,不加密,禁止存储敏感信息,如密码)。

Signature 部分用于确保令牌未被篡改,生成逻辑为:将 Header 编码字符串 + "." + Payload 编码字符串拼接后,用 Header 中指定的算法(如 HS256)和服务器端的 "密钥"(HS256 用对称密钥,RS256 用私钥)进行加密,得到的加密结果作为令牌第三部分。服务器验证时,会用相同逻辑重新计算签名,与令牌中的 Signature 对比,一致则令牌有效,不一致则判定为篡改。

用什么方式能在分布式部署中保存会话状态

第一种是分布式 Session(共享存储),将 Session 数据统一存储在分布式数据库或缓存中(如 Redis 集群、MySQL 主从),所有服务节点通过 "SessionID" 从共享存储中读取 / 写入 Session 数据 ------ 客户端首次请求时,节点生成 SessionID 并写入共享存储,后续请求携带 SessionID,任一节点均可通过 SessionID 从共享存储获取会话信息,适合需要维持传统 Session 逻辑的场景,需注意共享存储的高可用(如 Redis 集群)。

第二种是JWT 令牌,属于 "无状态会话" 方案,服务器无需存储 Session 数据,仅通过 JWT 令牌验证身份 ------ 客户端登录后,服务器签发 JWT 令牌(含用户 ID、过期时间等),客户端存储令牌,后续请求通过请求头携带令牌,任一节点均可通过本地解析令牌(验签、判断过期)完成身份验证,无需依赖共享存储,适合微服务、前后端分离架构,缺点是令牌无法主动吊销。

第三种是数据库共享会话,将 Session 数据直接存储在分布式数据库(如 MySQL 分库分表)中,结构通常为 "SessionID + 用户信息 + 过期时间",节点通过 SessionID 查询数据库获取会话状态,优点是数据持久化,缺点是数据库 IO 开销较大,适合会话数据需长期保留的场景。

第四种是Cookie + 加密,若会话信息较少(如仅用户 ID),可将用户信息加密后存储在 Cookie 中,客户端每次请求自动携带 Cookie,节点接收后解密 Cookie 获取会话信息 ------ 需注意加密(如 AES)和设置 Cookie 的安全属性(HttpOnly 防 XSS、Secure 仅 HTTPS 传输、SameSite 防 CSRF),缺点是受 Cookie 大小限制(通常 4KB),且依赖浏览器环境,不适合跨端场景。

JWT的缺点是什么

WT 的缺点主要集中在无法主动吊销、安全性局限、过期管理复杂三个方面。

首先是无法主动吊销令牌 ------JWT 签发后,服务器无法通过技术手段直接撤回或失效令牌,只能等待令牌自然过期(exp字段指定的时间),若令牌泄露(如被黑客窃取),即使立即发现,也无法阻止黑客在过期前使用令牌访问接口,只能通过额外手段(如维护 "令牌黑名单")补救,但黑名单会增加服务器存储和查询开销,违背 JWT "无状态" 的初衷。

其次是安全性局限,Payload 部分仅为 Base64Url 编码,并非加密,任何人获取令牌后均可通过解码查看 Payload 中的信息,因此绝对不能存储敏感数据(如密码、银行卡号);此外,若使用对称加密算法(如 HS256),服务器端的 "密钥" 一旦泄露,黑客可伪造任意 JWT 令牌,风险极高,需严格保管密钥(或改用非对称加密 RS256,私钥仅服务器持有)。

最后是过期管理复杂,JWT 的过期时间(exp)在签发时固定,无法动态调整,若需延长会话有效期,需重新签发新令牌(如 "刷新令牌" 机制:客户端携带过期的访问令牌和有效的刷新令牌,服务器验证刷新令牌后签发新访问令牌),增加了前后端交互逻辑;同时,令牌体积可能较大(若 Payload 携带较多自定义声明),会增加每次请求的头部开销,尤其在高频请求场景中影响传输效率。

JWT令牌泄露了怎么解决

首先是紧急止损措施:若项目中维护了 "JWT 黑名单"(如 Redis 存储已泄露的令牌),需立即将泄露的令牌加入黑名单,服务器验证时优先检查黑名单,命中则拒绝请求;若未维护黑名单,且令牌未过期,需紧急调整服务器端的 "密钥"(如 HS256 的对称密钥、RS256 的私钥)------ 密钥变更后,旧令牌(包括泄露的令牌)会因验签失败失效,但需注意:密钥变更会导致所有未过期的合法令牌失效,需通知用户重新登录,适合泄露影响范围大的场景。

其次是长期防护优化:一是缩短 JWT 的有效期(如访问令牌设置 15-30 分钟),同时引入 "刷新令牌" 机制 ------ 刷新令牌有效期较长(如 7 天),存储在客户端的 HttpOnly Cookie 中(防 XSS),访问令牌过期后,客户端用刷新令牌静默获取新访问令牌,即使访问令牌泄露,危害时间也被限制;二是强化前端存储安全,避免用 localStorage 存储 JWT(易被 XSS 攻击窃取),优先用 HttpOnly、Secure、SameSite 属性的 Cookie 存储,或在前端内存中临时存储(页面刷新后丢失);三是启用 HTTPS 传输,防止令牌在网络传输中被抓包窃取;四是监控异常请求,通过分析请求 IP、设备信息、访问频率等,识别异常使用的泄露令牌,及时触发告警或封禁。

前端如何存储JWT

前端存储 JWT 的方式主要有三种,各有优缺点,需根据业务安全性需求选择。第一种是localStorage ,将 JWT 存储在window.localStorage中,优点是存储容量大(约 5MB)、生命周期长(除非主动删除或清除浏览器数据),适合需要长期维持登录状态的场景;缺点是易受 XSS 攻击 ------ 黑客可通过注入恶意脚本读取 localStorage 中的 JWT,进而伪造请求,因此不建议存储敏感场景的 JWT(如支付、管理员权限)。

第二种是sessionStorage ,将 JWT 存储在window.sessionStorage中,优点是会话级存储,关闭浏览器标签页后自动清除,减少了令牌长期泄露的风险;缺点同样是易受 XSS 攻击,且无法跨标签页共享(如打开新标签页后需重新登录),适合短期会话场景(如临时访问页面)。

第三种是Cookie(推荐敏感场景) ,将 JWT 存储在 Cookie 中,需配置三个核心安全属性:HttpOnly(禁止 JavaScript 读取 Cookie,防 XSS 攻击)、Secure(仅通过 HTTPS 传输 Cookie,防网络抓包)、SameSite=Strict/Lax(限制 Cookie 跨域传输,防 CSRF 攻击);优点是安全性高,能有效抵御 XSS 和 CSRF 攻击,且 Cookie 会自动随请求携带,无需前端手动处理;缺点是受 Cookie 大小限制(约 4KB,JWT 需控制体积),且若需跨域传输,需额外配置Access-Control-Allow-Credentials等 CORS 属性,适合登录、支付等敏感场景。

实际项目中,推荐 "访问令牌 + 刷新令牌" 组合存储:访问令牌(短期,如 30 分钟)存在内存中(页面刷新后丢失,需用刷新令牌重新获取),刷新令牌(长期,如 7 天)存在带 HttpOnly 等安全属性的 Cookie 中,兼顾安全性和用户体验。

JWT刷新令牌机制
为什么有了HTTP还用RPC

HTTP 虽能满足基础的客户端 - 服务器通信,但在性能、服务治理、易用性上存在局限,RPC(远程过程调用)则针对这些痛点优化,因此在微服务、分布式系统中广泛使用。从性能来看,HTTP 基于文本传输,请求头冗余(如每次请求携带大量重复头部),且默认是 "请求 - 响应" 模式,连接复用效率低;而 RPC 通常基于二进制传输(如 gRPC 用 Protocol Buffers 序列化),数据体积小、解析速度快,且支持长连接、多路复用,能减少连接建立和传输的开销 ------ 例如微服务间高频通信(如订单服务调用库存服务),RPC 的性能优势会显著降低延迟,提升系统吞吐量。

从服务治理来看,HTTP 缺乏内置的服务治理能力,若需实现服务注册发现、负载均衡、熔断降级、超时重试等功能,需依赖第三方组件(如 Nginx、Spring Cloud Gateway);而 RPC 框架(如 Dubbo、gRPC、Thrift)通常内置了完整的服务治理体系 ------ 服务启动时自动注册到注册中心(如 ZooKeeper、Nacos),客户端通过注册中心获取服务地址,框架内置负载均衡(如轮询、哈希)、熔断降级(如 Hystrix),无需开发者额外开发,降低了分布式系统的复杂度。

从易用性来看,HTTP 通信需手动构造请求头、处理响应解析(如 JSON 转对象),尤其在多语言调用场景中(如 Java 服务调用 Python 服务),需统一数据格式和协议;而 RPC 支持 "语言原生调用",开发者可像调用本地方法一样调用远程服务(如 Dubbo 通过接口代理,gRPC 通过生成的客户端代码),框架自动处理序列化、网络传输、异常处理,减少了重复编码工作,提升开发效率。因此,HTTP 更适合外部通信(如前端调用后端 API),RPC 更适合内部服务间的高频、高性能通信。

HTTP的长连接和WebSocket有什么区别

HTTP 长连接和 WebSocket 虽都基于 TCP 连接,且能减少连接建立开销,但核心定位和通信模式完全不同,关键区别在通信方向、协议逻辑、适用场景三个方面。从通信方向来看,HTTP 长连接是 "单向通信(客户端主动)"------ 即使保持 TCP 连接,仍遵循 "客户端发起请求、服务器返回响应" 的模式,服务器无法主动向客户端推送数据;若需服务器主动推送(如实时通知),需客户端通过 "轮询"(定时请求)或 "长轮询"(请求挂起,有数据再响应)模拟,存在延迟或资源浪费。而 WebSocket 是 "全双工通信"------TCP 连接建立后(通过 HTTP 握手升级协议),客户端和服务器可双向、同时发送数据,服务器可主动向客户端推送数据(如聊天消息、实时弹幕),无需客户端主动请求,延迟极低。

从协议逻辑来看,HTTP 长连接基于 HTTP 协议,每次通信仍需携带完整的 HTTP 请求头(如 Host、User-Agent),即使是长连接,头部冗余仍存在;且连接的维持依赖Connection: keep-alive头部,服务器会配置空闲超时(如 60 秒),超时后关闭连接。而 WebSocket 通过 "协议升级" 建立连接(客户端发送Upgrade: websocket请求头,服务器响应101 Switching Protocols),升级后脱离 HTTP 协议,后续通信仅需携带少量帧头部(如 opcode、mask),数据传输效率更高;且连接默认长期维持,除非主动断开或网络异常,无空闲超时限制(可自定义心跳机制维持连接)。

从适用场景来看,HTTP 长连接适合 "客户端高频请求、服务器被动响应" 的场景(如网页加载多个图片、API 接口批量查询),能减少 TCP 连接建立次数;而 WebSocket 适合 "实时双向通信" 的场景(如在线聊天、实时监控、股票行情推送),能实现低延迟、高实时性的双向数据传输,避免轮询带来的资源浪费。

Nginx 有哪些负载均衡算法

Nginx 的负载均衡算法分为内置算法第三方算法(需编译安装模块),内置算法中常用的有五种。

第一种是轮询(默认),将请求按顺序平均分配给每个后端服务器,若某台服务器宕机,Nginx 会自动剔除该服务器,后续请求不再分配,适合所有服务器配置相同、负载能力一致的场景(如微服务集群节点)。

第二种是加权轮询(weight),为每个后端服务器配置权重,请求按权重比例分配,权重越高的服务器接收请求越多,适合服务器配置不同的场景,能充分利用服务器资源。

第三种是IP 哈希(ip_hash),根据客户端 IP 地址的哈希值分配服务器,同一 IP 的客户端会固定访问同一台服务器,能实现 "会话保持"(如用户登录后,后续请求仍到同一节点,避免分布式 Session 问题),缺点是若某台服务器宕机,该 IP 对应的客户端会切换到其他服务器,需重新登录。

第四种是最少连接(least_conn),Nginx 会实时统计后端服务器的活跃连接数,将新请求分配给连接数最少的服务器,适合请求处理时间差异较大的场景(如部分请求耗时久,导致服务器连接数堆积),能动态平衡各服务器的负载。

第五种是URL 哈希(url_hash,需开启 ngx_http_upstream_hash_module 模块) ,根据请求 URL 的哈希值分配服务器,同一 URL 的请求会固定到同一台服务器,适合缓存场景(如静态资源服务器,同一 URL 的资源缓存到同一节点,减少缓存失效),需手动开启模块(编译时添加--with-http_upstream_hash_module)。

第三方算法中,常见的有一致性哈希(如 ngx_http_consistent_hash_module),解决传统哈希算法在服务器上下线时 "哈希重排" 导致的大量请求切换节点问题,适合后端服务器频繁变更的场景(如云环境中节点动态扩缩容)。

Nginx 在网络分层中的哪一层

Nginx 属于OSI 模型的应用层(对应 TCP/IP 模型的应用层),核心原因是 Nginx 的核心功能是处理应用层的业务逻辑(如请求解析、负载均衡、静态资源返回)。从功能来看,Nginx 主要处理 HTTP、HTTPS、TCP、UDP 等协议的请求:作为 Web 服务器时,解析 HTTP 请求(如请求行、头部),处理静态资源(HTML、CSS)或反向代理到后端应用服务器;作为反向代理时,转发 HTTP/HTTPS 请求到后端节点,实现负载均衡;即使是处理 TCP/UDP 请求(如转发 MySQL、Redis 的连接),Nginx 也仅作为 "应用层代理",不参与 TCP 协议的三次握手、四次挥手等底层逻辑,仅在应用层接收请求后转发到后端,本质是对应用层数据的处理和路由。

虽然 Nginx 会建立和管理 TCP 连接(如与客户端建立 TCP 连接,再与后端建立 TCP 连接),但Nginx 不修改 TCP 协议的传输逻辑(如滑动窗口、重传),仅利用 TCP 提供的可靠传输能力,处理应用层的业务逻辑(如请求解析、负载均衡、静态资源返回)。因此,Nginx 的核心功能属于应用层,是应用层的 "中间件",而非传输层或网络层的设备(如路由器工作在网络层,交换机工作在数据链路层)。

传输层

说一下TCP的头部

TCP 头部是 TCP 协议实现可靠传输的核心控制结构,固定部分为 20 字节,可选字段最多 40 字节。头部起始是 2 字节的源端口和 2 字节的目的端口,用于标识通信双方的应用进程,结合 IP 地址可精确定位到具体进程;紧接着是 4 字节的序列号(seq),标记当前 TCP 段第一个字节的序号,例如 SYN 报文的 seq 为随机生成的初始序列号(ISN),确保数据有序 和 去重;随后是 4 字节的确认号(ack),仅当 ACK 控制位为 1 时有效,表示期望接收的下一个字节序号,用于确认已收到的数据。头部中间的 6 位控制位中,SYN 位用于发起连接,ACK 位用于确认接收,FIN 位用于断开连接,RST 位用于强制关闭异常连接,三次握手主要依赖 SYN 和 ACK 位。此外,2 字节的窗口大小用于告知接收方当前可接收的最大字节数,实现流量控制;2 字节的校验和用于校验头部和数据的完整性,接收方校验失败会丢弃该段。还有紧急指针和选项字段(如协商最大段大小 MSS),共同支撑 TCP 的可靠、有序传输。

字段名称 字节数 核心作用
源端口 2 标识发送方的应用程序(如 HTTP 的 80、HTTPS 的 443)
目的端口 2 标识接收方的应用程序
序号 4 标记当前数据段中 "第一个字节" 的编号(可靠传输的核心,确保数据有序 和 去重)
确认号 4 标记 "期望接收的下一个字节的编号"(仅当 ACK 标志位为 1 时有效,确认已收数据)
数据偏移 4 表示 TCP 头部的总长度(单位:4 字节),定位数据段的开始位置(最小 5=20 字节)
保留位 6 预留未来使用,目前固定为 0
控制位 6 6 个标志位,控制连接建立、关闭、数据优先级等(如 SYN、ACK、FIN)
窗口大小 2 告知对方 "当前自己的接收缓冲区剩余空间大小"(流量控制的核心)
校验和 2 验证 TCP 头部 + 数据的完整性(发送方根据tcp头部和数据计算,接收方同理校验,错误则丢弃)
紧急指针 2 仅 URG 标志位为 1 时有效,指向紧急数据的末尾(优先处理紧急数据)
选项 0-40 可选功能(如协商最大段大小 MSS、窗口扩大因子、时间戳等),需 4 字节对齐
说一下TCP三次握手的过程

第一次握手由客户端主动发起:客户端会构建一个 TCP 报文,其中控制位仅SYN(同步)标志设为 1,同时生成一个随机的初始序号,若有需要还会携带MSS(最大段大小)等可选字段,用于协商后续数据传输的参数。该报文发送至服务器后,客户端的状态从CLOSED切换为SYN_SENT,表示已发送连接请求,等待服务器响应;服务器收到这个SYN报文后,确认有客户端请求连接,状态从LISTEN切换为SYN_RCVD,进入等待客户端最终确认的阶段。

第二次握手由服务器响应客户端的请求:服务器会生成一个新的 TCP 报文,此时控制位需同时设置SYN=1 和ACK=1,SYN=1 用于同步服务器自身的随机初始序号(ISN_s,比如取值为 y),ACK=1 则用于确认已收到客户端的SYN报文,因此确认号字段会设为ISN_c + 1(即 x+1,含义是 "已接收客户端序号 x 及之前的所有数据,下次期望接收 x+1"),同时也会在可选字段中回复服务器支持的MSS值。这个SYN+ACK报文发送给客户端后,服务器保持SYN_RCVD状态不变;客户端收到该报文后,确认服务器已同意连接且能正常收发数据,状态从SYN_SENT切换为ESTABLISHED,此时客户端侧的连接已初步建立,可准备后续数据传输。

第三次握手由客户端向服务器发送最终确认:客户端构建的 TCP 报文仅需将控制位ACK设为 1,序号字段使用ISN_c + 1(即 x+1,作为客户端下一个数据段的起始序号,若此时有应用层数据需传输,也可直接携带在该报文中),确认号字段则设为ISN_s + 1(即 y+1,含义是 "已接收服务器序号 y 及之前的所有数据,下次期望接收 y+1")。该ACK报文发送至服务器后,服务器收到并验证确认号无误,确认客户端能正常接收自己的响应,状态从SYN_RCVD切换为ESTABLISHED,至此 TCP 三次握手完成,客户端与服务器均进入连接就绪状态,可正式开始传输应用层数据(如 HTTP 请求、文件数据等)。

TCP三次握手,客户端第三次发送的确认包丢失会发生什么

客户端第三次发送的 ACK 丢失后,客户端与服务器的连接状态会出现暂时不一致。客户端发送 ACK 后已进入 ESTABLISHED 状态,认为连接已建立,若有数据需传输会直接发送带数据的 TCP 段(含 ACK 确认),若无数据则等待服务器后续报文。服务器仍处于 SYN_RCVD 状态,会启动 SYN+ACK 超时重传定时器,按指数退避策略重传 SYN+ACK(默认重传 5 次,超时时间翻倍)。若重传期间服务器收到客户端的 ACK(可能是重传的单独 ACK 或带数据的 ACK),则从 SYN_RCVD 进入 ESTABLISHED 状态,连接正常;若重传失败,服务器会退回 LISTEN 状态并释放资源,后续客户端发送数据时,服务器会回复 RST 报文告知连接失效,客户端随后关闭连接。

服务端发送第二个报文后(第二次握手后)连接会进入什么状态

服务端发送第二个报文(SYN+ACK 报文)后,连接会从 LISTEN 状态(监听客户端连接请求的状态)切换到 SYN_RCVD 状态。该状态表示服务器已接收客户端的 SYN 请求,完成了自身序列号的同步并确认了客户端的序列号,但尚未收到客户端对自己 SYN 的最终确认(即第三次握手的 ACK),处于等待客户端最终确认的中间状态,需等收到 ACK 后才会进入 ESTABLISHED 状态,完成连接建立。

三次握手和accept是什么关系,accept做了那些事

三次握手与 accept 分属不同层级,三次握手是操作系统内核完成的 TCP 连接建立过程,无需应用层干预;accept 是应用层通过 Socket 编程调用的系统调用,用于获取内核已建立的连接,即 "三次握手建连接,accept 取连接"。具体而言,三次握手完成后,服务器内核会将已建立的连接放入 "已完成连接队列",应用层调用 accept 时,会先检查队列是否为空,若为空则阻塞等待,直至队列有连接;队列有连接时,accept 会取出一个连接,为其分配新的文件描述符,用于与客户端读写数据,随后返回该 fd 给应用层。

客户端发送的第一个SYN报文,服务器没有收到怎么办

服务器未收到客户端的第一个 SYN 报文时,会保持 LISTEN 状态,无任何动作,因服务器未感知到连接请求。客户端发送 SYN 后进入 SYN_SENT 状态,同时启动 SYN 超时重传定时器(初始超时约 1s),若超时未收到服务器的 SYN+ACK,会按指数退避策略重传 SYN(默认重传 5 次,超时时间翻倍)。若所有重传失败,客户端会判定连接建立失败,从 SYN_SENT 退回 CLOSED 状态

客户端发送第一个SYN报文,服务器回复的SYN+ACK丢失了怎么办

这种情况下,客户端与服务器会分别触发超时重传,修复连接认知不一致。客户端处于 SYN_SENT 状态,未收到 SYN+ACK 会启动 SYN 超时重传定时器,按指数退避策略重传 SYN,直至失败后关闭连接。服务器处于 SYN_RCVD 状态,未收到客户端 ACK 会启动 SYN+ACK 超时重传定时器,同样按指数退避策略重传 SYN+ACK(默认 5 次)。若客户端重传的 SYN 被服务器收到,服务器再次回复 SYN+ACK;若服务器重传的 SYN+ACK 被客户端收到,客户端发送第三次 ACK,三次握手可继续完成;若双方重传均失败,客户端退回 CLOSED 状态,服务器退回 LISTEN 状态,连接建立失败。

第一次握手,客户端发送SYN报文后,服务端回复ACK报文,那这个过程中服务端内部做了哪些工作?

服务端此时回复的是 SYN+ACK 报文(非单纯 ACK),核心是同步自身序列号并确认客户端 SYN,内部工作主要包括:首先进行端口与状态验证,内核检查客户端请求的目的端口是否已被应用层 bind () 绑定且 listen () 监听,若未监听则丢弃 SYN,不回复;若已监听且处于 LISTEN 状态,则继续处理。其次分配连接资源,内核为该连接创建 TCP 控制块(TCB),存储客户端 IP、端口、服务器 IP、端口、服务器随机初始序列号(ISN_S)、客户端 SYN 的序列号(ISN_C)、窗口大小、连接状态等信息,同时分配接收缓冲区。然后构造 SYN+ACK 报文,按 TCP 头部格式组装:SYN=1、ACK=1,seq=ISN_S,ack=ISN_C+1,窗口大小设为接收缓冲区初始可用大小,计算校验和。接着发送报文并切换状态,通过网络驱动发送 SYN+ACK,连接状态从 LISTEN 切换到 SYN_RCVD。最后启动 SYN+ACK 超时重传定时器,设置初始超时时间,若未收到客户端 ACK 则会重传。

客户端重传了SYN报文,服务器又收到了重复的SYN报文怎么办

服务器收到重复的 SYN 报文(如客户端超时重传的 SYN),因无法区分是重传还是新请求,会按 "第一次收到 SYN" 的逻辑处理,再次回复 SYN+ACK 报文。具体来说,服务器会先检查目标端口是否仍在监听,若在监听,若已为该客户端(IP + 端口)分配 TCP 控制块(TCB)且处于 SYN_RCVD 状态,则复用该 TCB 并更新 SYN+ACK 超时定时器;随后构造与第一次相同的 SYN+ACK 报文(seq 为服务器 ISN,ack 为客户端 SYN 的 seq+1),发送后保持 SYN_RCVD 状态。客户端收到重复的 SYN+ACK 后,会再次发送第三次握手的 ACK,服务器收到后进入 ESTABLISHED 状态,连接正常建立。

大量SYN包发送给服务端会发生什么

大量 SYN 包发送给服务端,本质是 SYN 洪水攻击(DDoS 的一种),核心会导致服务端 "半连接队列耗尽" 并引发资源过载。服务端收到 SYN 包后,会从 LISTEN 状态进入 SYN_RCVD 状态,同时为每个 SYN 请求分配 TCP 控制块(TCB)等资源,并存入 "半连接队列"(用于存放已接收 SYN 但未完成三次握手的连接)。当 SYN 包数量远超半连接队列容量(默认通常几百到几千),队列会满,后续正常的 SYN 请求会被直接丢弃,导致合法客户端无法建立连接。此外,大量 TCB 资源占用会消耗服务器的内存、CPU,甚至耗尽端口资源,进一步导致服务端性能骤降,无法处理其他业务请求。部分服务器会开启 SYN Cookie 机制缓解:不直接分配 TCB,而是通过算法生成带验证信息的 SYN+ACK,仅当收到客户端的 ACK 时才验证并建立连接,减少资源浪费,但仍无法完全抵消大量请求带来的网络带宽占用

说一下TCP四次挥手的过程

TCP 四次挥手是客户端与服务器断开可靠连接的过程,核心是 "双向关闭连接",需区分主动断开方和被动断开方(假设客户端先主动断开):

第一次挥手由主动关闭方(客户端)发起:客户端决定不再发送数据,会构建一个 TCP 报文,控制位FIN(结束)标志设为 1(表示 "我已无数据要发送,请求关闭我的发送通道"),序号字段为客户端当前的发送序号(假设为u,即最后一次发送数据的最后一个字节序号 + 1),确认号字段为 "已收到服务器的最新数据序号 + 1"(假设为v,表示对服务器之前数据的正常确认)。该报文发送后,客户端状态从ESTABLISHED切换为FIN_WAIT_1(等待服务器对 FIN 的确认)。

第二次挥手由被动关闭方(服务器)响应:服务器收到客户端的 FIN 报文后,确认客户端要关闭发送通道,会立即回复一个 ACK 报文 ------ 控制位ACK=1,序号字段为服务器当前的发送序号(假设为v),确认号字段为u + 1(表示 "已收到客户端的 FIN 报文,序号 u 及之前的数据均已接收")。发送该 ACK 后,服务器状态从ESTABLISHED切换为CLOSE_WAIT(半关闭状态,此时服务器仍可向客户端发送数据,仅客户端的发送通道关闭);客户端收到该 ACK 后,状态从FIN_WAIT_1切换为FIN_WAIT_2(确认服务器已收到关闭请求,等待服务器自己的 FIN 报文)。

第三次挥手由被动关闭方(服务器)发起:服务器完成所有待发送数据后,决定关闭自己的发送通道,会发送一个 FIN 报文 ------ 控制位FIN=1 且ACK=1(ACK=1 是对客户端数据的持续确认),序号字段为服务器最后一次发送数据的最后一个字节序号 + 1(假设为w),确认号字段仍为u + 1(与第二次挥手一致,因客户端未再发送新数据)。发送该 FIN 后,服务器状态从CLOSE_WAIT切换为LAST_ACK(等待客户端对 FIN 的最终确认)。

第四次挥手由主动关闭方(客户端)响应:客户端收到服务器的 FIN 报文后,确认服务器也关闭了发送通道,会回复一个 ACK 报文 ------ 控制位ACK=1,序号字段为u + 1(客户端的下一个发送序号),确认号字段为w + 1(表示 "已收到服务器的 FIN 报文,序号 w 及之前的数据均已接收")。发送该 ACK 后,客户端状态从FIN_WAIT_2切换为TIME_WAIT(等待一段时间,确保服务器收到该 ACK),而服务器收到 ACK 后,状态从LAST_ACK直接切换为CLOSED(连接完全关闭)。客户端在TIME_WAIT状态等待 "2 倍最大报文段寿命(2MSL)" 后,也切换为CLOSED,至此四次挥手完成。

为什么四次挥手中间两次不能变成一次

四次挥手中间两次(被动断开方的 ACK 和 FIN)不能合并,核心原因是 TCP 是 "全双工通信",需分别关闭 "两个方向的数据流",且被动断开方可能存在 "未发送完的数据"。具体来说:第一次挥手是主动方关闭 "自己的发送方向",被动方收到后需先回复 ACK(第二次挥手),确认 "已感知主动方的发送方向关闭",此时被动方可能仍有未传输完的业务数据(如服务器还有未返回给客户端的结果),需继续发送数据,无法立即发送 FIN;只有当被动方完成所有数据传输,确认无需再发送后,才会发起 FIN(第三次挥手),关闭 "自己的发送方向"。若合并两次挥手,被动方需在收到 FIN 的同时发 FIN,会导致未传输的数据丢失,违背 TCP 可靠传输的原则;同时,全双工的两个方向关闭是独立的,必须分步骤确认,无法通过一次报文完成。

TCP第三次挥手一直没发会发生什么

TCP 第三次挥手是被动断开方发送的 FIN 报文,若一直没发,会导致双方连接状态长期滞留,资源浪费。具体来看:主动断开方在发送第一次 FIN(第一次挥手)、收到被动方的 ACK(第二次挥手)后,会进入 FIN_WAIT_2 状态,等待被动方的 FIN;而被动方收到 FIN 后进入 CLOSE_WAIT 状态,若因应用层问题(如服务进程未调用 close () 函数释放连接、代码 bug 导致资源未回收),一直不发送 FIN,会长期停留在 CLOSE_WAIT 状态。此时,主动方的 FIN_WAIT_2 状态会持续存在(部分系统会设置 FIN_WAIT_2 超时时间,超时后主动断开),被动方的 CLOSE_WAIT 状态会堆积大量连接,占用服务器的 TCB、内存、端口等资源,导致新连接无法建立,甚至引发服务性能下降或崩溃。

第二次挥手和第三次挥手之间,主动断开的那端能干什么

第二次挥手和第三次挥手之间,主动断开的一端(如客户端)处于 FIN_WAIT_2 状态,此时它只能接收数据,不能发送数据。因为第一次挥手后,主动断开方已关闭 "自己的发送方向",告知被动方 "不再发送数据",所以无法再向被动方传输新数据;但 TCP 是全双工通信,被动方的发送方向仍未关闭,可能还有未传输完的数据需要发送给主动方,因此主动断开方需保持接收能力,等待被动方发送完数据后发起第三次挥手(FIN)。若主动断开方此时收到被动方的数据,会正常接收并回复 ACK;若被动方一直不发数据也不发 FIN,主动方会在 FIN_WAIT_2 超时后主动断开连接,释放资源。

断开连接时客户端(主动断开方)FIN包丢失,服务端(被动断开方)的状态是什么

断开连接时若客户端(主动断开方)发送的 FIN 包丢失,服务端会保持 ESTABLISHED 状态不变,完全感知不到客户端的断开请求。因为服务端未收到 FIN 包,无法判断客户端要断开连接,会继续认为连接正常,等待客户端发送数据或新的请求;而客户端发送 FIN 后会进入 FIN_WAIT_1 状态,启动 FIN 超时重传定时器,按指数退避策略重传 FIN 包(默认重传 5 次)。若重传期间服务端仍未收到 FIN,客户端会在重传失败后从 FIN_WAIT_1 进入 CLOSED 状态,释放资源;但服务端仍处于 ESTABLISHED 状态,该连接会成为 "僵尸连接",长期占用服务器的 TCB、内存等资源,直到服务端因 "连接空闲超时"(如 TCP keepalive 机制检测到连接失效)或应用层主动关闭,才会释放资源。

为什么四次挥手之后还要等2MSL

四次挥手后主动断开方(如客户端)需等待 2MSL(MSL 是 "报文最大生存时间",默认约 30 秒,不同系统略有差异),核心是为了确保连接彻底关闭,避免旧报文干扰新连接,主要有两个原因:一是 "确保最后一个 ACK 被被动方收到":主动断开方发送第四次挥手的 ACK 后,若该 ACK 丢失,被动方(处于 LAST_ACK 状态)会重传 FIN 报文。2MSL 是报文在网络中往返的最大时间,主动方等待 2MSL,能确保收到被动方重传的 FIN(若有),并再次发送 ACK,避免被动方因未收到 ACK 而长期滞留 LAST_ACK 状态;若 2MSL 内未收到重传的 FIN,说明被动方已收到 ACK 并进入 CLOSED 状态,连接可安全关闭。二是 "避免旧连接的报文干扰新连接":网络中可能存在延迟的旧报文(属于本次断开的连接),若主动方不等待 2MSL 直接进入 CLOSED 状态,立即用相同的 IP 和端口建立新连接,旧报文可能会误进入新连接,导致新连接的数据解析错误。2MSL 内,网络中的旧报文会自然过期或被丢弃,确保新连接不会受到旧报文的干扰,保证连接的唯一性和数据安全性。

服务端出现大量的time_wait有哪些原因

服务端出现大量 TIME_WAIT 状态,核心是服务端作为 "主动断开连接的一方",且连接关闭后未及时释放资源,常见原因集中在连接模式、关闭逻辑和系统配置上。首先是短连接频繁建立与断开,比如 HTTP/1.1 未启用长连接(Connection: keep-alive),每次请求完成后服务端主动关闭连接,会进入 TIME_WAIT 状态;若业务场景中短连接并发量高(如高频 API 调用),大量连接短时间内断开,会导致 TIME_WAIT 堆积。其次是服务端业务逻辑主动触发关闭,比如部分业务设计中,服务端处理完请求后会主动调用 close () 函数断开连接(而非客户端主动断开),每次主动关闭都会让服务端进入 TIME_WAIT。另外,系统的 2MSL(报文最大生存时间)配置过长,默认 2MSL 约 30-60 秒,若大量连接在 2MSL 周期内集中断开,会导致 TIME_WAIT 状态持续时间长,超过系统回收速度;还有可能是端口复用机制未合理配置,服务端使用固定端口提供服务,TIME_WAIT 状态的连接会占用端口,新连接无法复用,进一步加剧端口和 TIME_WAIT 的堆积。

TCP和UDP区别是什么

TCP 和 UDP 是传输层两种核心协议,核心区别体现在连接性、可靠性、传输逻辑和适用场景上。TCP 是面向连接的协议,需通过三次握手建立连接、四次挥手断开连接,确保通信双方状态同步;UDP 是无连接协议,发送数据前无需建立连接,直接将数据封装成报文发送,不关心对方是否接收。可靠性方面,TCP 通过序列号、确认号、超时重传、流量控制、拥塞控制等机制实现可靠传输,能保证数据不丢失、不重复、有序到达;UDP 无可靠性保障,不提供重传、确认机制,数据可能丢失、乱序,仅通过校验和确保数据传输中不损坏,损坏则直接丢弃。传输逻辑上,TCP 是面向字节流的,会将应用层数据拆分成字节流,按序传输,接收方需自行拼接数据;UDP 是面向报文的,会保留应用层数据的边界,发送方发一个报文,接收方收一个报文,不拆分也不合并。头部开销上,TCP 头部固定 20 字节,含序列号、确认号等控制字段,开销大;UDP 头部仅 8 字节,含源端口、目的端口、长度和校验和,开销小。适用场景上,TCP 适合对可靠性要求高的场景(如文件传输、HTTP/HTTPS、数据库连接),UDP 适合对延迟敏感、可容忍少量丢包的场景(如直播、视频通话、DNS 查询、物联网设备通信)。

TCP传输为什么可靠

TCP 传输可靠,核心是通过多维度机制确保数据 "不丢失、不重复、有序到达"。首先是连接建立阶段的三次握手,通过同步双方初始序列号(ISN),确保通信双方都能正常收发数据,避免 "一方能发但另一方收不到" 的无效连接。其次是序列号与确认号机制,TCP 为每个字节的数据分配唯一序列号,接收方收到数据后,会回复确认号(已接收数据的最大序列号 + 1),告知发送方 "已收到哪些数据,下一步期望接收什么",若发送方未收到确认号,会判定数据丢失并触发重传。重传机制进一步保障可靠性,包括超时重传(发送方启动定时器,超时未收确认则重传)和快速重传(收到 3 个重复确认号,立即重传丢包的段,无需等待超时),确保丢失的数据能及时补传。此外,TCP 的流量控制通过滑动窗口实现,接收方告知发送方自己的缓冲区可用大小,发送方按窗口大小调整发送速率,避免接收方缓冲区溢出导致数据丢失;拥塞控制(慢启动、拥塞避免等)则通过控制发送速率,避免网络过载导致丢包,间接保障传输可靠。最后,TCP 头部的校验和会对头部和数据进行校验,接收方校验失败会丢弃数据,避免损坏的数据被应用层使用,这些机制共同构成了 TCP 的可靠传输能力。

TCP粘包、拆包是什么,怎么解决

TCP 粘包、拆包是 TCP 字节流特性导致的现象:TCP 是面向连接的字节流协议,不维护数据边界

  • 粘包:发送方连续发送的多个小数据包,因 TCP 的 Nagle 算法(合并小数据包减少网络开销)或接收方缓冲区未及时读取,被合并成一个大包到达接收方;或前一个数据包的剩余部分与后一个数据包 "粘" 在一起。
  • 拆包:发送方发送的单个大数据包,因超过 TCP MSS(最大分段大小,由 MTU 衍生)或发送缓冲区限制,被 TCP 拆分成多个小包传输,接收方需多次读取才能凑齐完整数据包。

核心是在应用层加 "数据边界",让接收方能拆分:一是固定长度,约定所有包大小一致,接收方按固定长度读,简单但易浪费带宽;二是加分隔符,每个包末尾加特殊标识(如\n),接收方按标识拆分,需避免标识和数据冲突;第三种是消息头部带长度,约定消息结构为 "头部 + 体",头部固定字节数(如 4 字节),存储消息体的总长度;发送方先发送头部(告知消息体长度),再发送消息体;接收方先读取头部,解析出消息体长度,再读取对应长度的消息体,能精准拆分消息,适合二进制或变长文本数据,是最常用的方案(如 HTTP 的 Content-Length 字段)。第四种是应用层协议定义,通过标准化协议明确消息边界,比如 HTTP 协议通过 \r\n\r\n 分隔请求头和请求体,同时用 Content-Length标识请求体长度,本质是结合了分隔符和长度标识,确保不同场景下的粘包问题都能解决。

说一下TCP流量控制

TCP 流量控制的核心是解决 "发送方速率过快、接收方处理不及" 的问题,避免接收方缓冲区溢出导致丢包,是仅作用于 "发送方 - 接收方" 的端到端机制。

其实现依赖 TCP 头部的 "接收窗口(rwnd)" 字段:接收方每次回复 ACK 确认时,会将当前 "剩余缓冲区空间大小" 封装成 rwnd,告知发送方。发送方的发送速率严格受 rwnd 约束 ------ 若 rwnd 较大,可适当多发数据;若 rwnd 减小(接收方处理变慢),则减少发送量;若 rwnd=0(接收方缓冲区满),发送方会暂停发送,直到接收方处理完数据、缓冲区有空闲后,主动发送携带新 rwnd 的 ACK,发送方才恢复传输。

简单来说,流量控制通过 "接收方告知发送方'能接多少',发送方就'发多少'" 的逻辑,实现发送速率与接收方处理能力的精准匹配。

TCP怎么检测到丢包发生的

超时重传是最基础的机制。发送方在发送每个数据包时,会启动一个计时器,若在计时器超时前未收到该数据包对应的确认 ACK,就判定该数据包已丢失,随即触发重传。这种机制适用于网络延迟较大或数据包彻底丢失的场景,但缺点是等待超时可能耗时较长。

快速重传则是更及时的补充机制。当接收方收到失序的数据包(比如期望收到序号 100 的包,却先收到了 101),会重复发送最近已正确接收的有序数据包的 ACK(即持续发送 ACK 100)。发送方若连续收到 3 个相同的重复 ACK,就可推断出对应序号的数据包(这里的 100)已丢失 ------ 因为接收方只有在收到后续包但缺失中间包时,才会频繁重复确认。此时发送方无需等待超时,直接重传丢失的数据包,大幅缩短了丢包检测的时间。

说一下TCP拥塞控制

TCP 拥塞控制的核心是 "避免发送方发送速率超过网络承载能力",防止网络拥塞导致丢包,主要通过 "拥塞窗口(cwnd)" 和 "慢启动阈值(ssthresh)" 两个参数调控,分为四个阶段。第一个阶段是慢启动,连接刚建立时,cwnd 初始值为 1(单位是 MSS,最大段大小),每次收到确认号(ACK),cwnd 按指数增长(1→2→4→8...),直到 cwnd 达到 ssthresh(默认由系统设置,如 65535 字节);这个阶段的目的是快速探测网络的初始承载能力,避免一开始就发送大量数据导致拥塞。第二个阶段是拥塞避免,当 cwnd 超过 ssthresh 后,慢启动结束,进入拥塞避免阶段,此时 cwnd 不再指数增长,而是每次收到 ACK 后按线性增长(每次 + 1),缓慢增加发送速率,平衡吞吐量和网络稳定性,若出现超时丢包,会将 ssthresh 设为当前 cwnd 的一半,cwnd 重置为 1,重新进入慢启动。第三个阶段是快速重传,若发送方收到 3 个相同的重复确认号,无需等待超时,立即重传丢失的段,同时将 ssthresh 设为当前 cwnd 的一半,cwnd 设为 ssthresh,进入快速恢复阶段,避免超时导致的发送速率骤降。第四个阶段是快速恢复,重传丢失的段后,每次收到一个确认号,cwnd 按线性增长(每次 + 1),直到 cwnd 恢复到拥塞前的水平,再进入拥塞避免阶段,直到再次检测到拥塞,循环调整;这个阶段的目的是在丢包后快速恢复发送速率,减少对吞吐量的影响。整体来看,TCP 拥塞控制通过 "探测 - 调整 - 恢复" 的循环逻辑,动态适配网络状况,在避免拥塞的同时最大化利用网络带宽。

怎么用 UDP 实现 HTTP

HTTP 默认基于 TCP 传输,若用 UDP 实现,核心是解决 UDP"无连接、不可靠" 的缺陷,同时兼容 HTTP 的应用层语义,需从传输可靠性、数据边界、会话管理三方面设计。首先要实现基于 UDP 的可靠传输机制,因为 UDP 不提供重传和确认,需在应用层模拟 TCP 的核心逻辑:为每个 HTTP 请求 / 响应分配序列号,发送方发送数据后启动定时器,超时未收到确认则重传;接收方收到数据后,回复确认号(含已接收的最大序列号),若数据乱序则暂存,按序列号拼接后再交给应用层,确保数据不丢失、有序到达。其次要处理数据边界,UDP 面向报文但 HTTP 请求 / 响应有结构化数据(如请求头、请求体),需定义 UDP 帧格式,比如约定 "帧头部(4 字节长度 + 会话 ID)+ HTTP 数据",头部的长度字段标识当前帧的 HTTP 数据长度,会话 ID 用于区分不同的 HTTP 请求(因 UDP 无连接,需通过会话 ID 关联请求和响应),接收方先解析头部,再读取对应长度的 HTTP 数据,避免数据粘包或拆分错误。然后要实现会话管理,HTTP 的会话(如 Cookie 维持的登录状态)需在应用层关联,通过在 UDP 帧的会话 ID 中携带客户端标识(如 Cookie 的 SessionID),服务端根据会话 ID 识别客户端,维持会话状态,确保多次 UDP 请求能关联到同一用户。最后要兼容 HTTP 语义,确保 HTTP 的请求方法(GET/POST)、状态码(200/404)、头部字段(Host/Content-Type)等逻辑不变,仅将底层传输从 TCP 换成自定义的可靠 UDP 协议,同时处理并发请求(通过不同的会话 ID 或端口区分)。实际中,QUIC 协议就是基于 UDP 实现的类似方案(HTTP/3 基于 QUIC),通过内置的可靠性机制、帧结构和会话管理,既保留 UDP 的低延迟优势,又实现了 HTTP 所需的可靠性和语义兼容。

网络攻击

什么是DDoS攻击,怎么防范

DDoS 攻击(分布式拒绝服务攻击)是攻击者通过控制大量 "傀儡机"(如被感染的电脑、物联网设备),向目标服务器或网络发起海量无效请求(如 SYN 洪水、UDP 洪水、HTTP 洪水),耗尽目标的带宽、CPU、内存等资源,导致正常用户无法访问服务的攻击方式。而DDos的第一个D是它区别于单点的 DoS 攻击的根本,依赖分布式节点形成的 "流量洪流",破坏力更强,而且能隐藏攻击者。

防范需从 "流量拦截、资源保护、监控响应" 多层面入手:首先可借助 CDN(内容分发网络)或高防 IP,将攻击流量引流到高防节点进行清洗,过滤掉恶意流量后再将正常请求转发给源站,避免源站直接暴露在攻击下;其次配置网络层防护,如防火墙开启 SYN Cookie 抵御 SYN 洪水,限制单 IP 的并发请求数,避免单节点被过度占用;服务器层面需优化资源配置,如增加内存、提升带宽,启用连接复用(如 HTTP 长连接)减少连接开销,同时部署负载均衡分散流量,避免单点故障;最后需建立实时监控和应急响应机制,通过流量分析工具(如 Wireshark、Zabbix)监控异常流量,一旦发现攻击立即切换高防线路、调整防护策略,甚至暂时屏蔽攻击源 IP 段,最大限度降低服务中断时间。

SQL注入问题是什么,怎么防范

SQL 注入是攻击者通过在用户输入框(如登录账号、搜索框)中插入恶意 SQL 语句(如' OR 1=1 --),让后端数据库执行非预期操作的漏洞。例如登录场景中,若后端直接拼接用户输入为SELECT * FROM user WHERE username='{$input}' AND password='{$input}',攻击者输入' OR 1=1 --后,SQL 会变成SELECT * FROM user WHERE username='' OR 1=1 --' AND password=''OR 1=1让条件恒成立,--注释掉后续内容,从而绕过登录验证,甚至获取数据库所有数据、删除表结构。

防范核心是 "杜绝 SQL 语句拼接,分离代码与数据":最有效的方式是使用参数化查询(预处理语句),如 JDBC的PreparedStatement或者MyBatis的#{},后端先定义带占位符的 SQL 模板(如SELECT * FROM user WHERE username=? AND password=?),再将用户输入作为参数传入,数据库会自动区分参数和 SQL 指令,避免恶意语句被解析;其次需做输入验证与过滤,对用户输入的特殊字符(如';ORAND)进行转义(如将'转成''),或限制输入格式(如手机号仅允许数字),减少注入可能性;还需遵循最小权限原则,数据库账号仅授予必要权限(如查询账号不具备删除、修改表的权限),即使发生注入,也能降低损失;此外避免在页面显示详细 SQL 错误信息(如报错内容含表名、字段名),防止攻击者利用错误信息构造更精准的注入语句。

CSRF攻击是什么,怎么防范

CSRF 攻击(跨站请求伪造)是攻击者利用用户已登录的身份,在用户不知情的情况下,诱导用户访问恶意页面或点击恶意链接,发起针对目标网站的 "伪造请求",完成非预期操作(如转账、改密码、发表评论)。例如用户登录银行网站后未退出,又打开攻击者的钓鱼页面,页面中隐藏的<img src="https://bank.com/transfer?to=attacker&money=1000">会自动发起转账请求,银行服务器因用户已登录(Cookie 有效),会误认为是用户主动操作,从而执行转账。

防范核心是 "验证请求来源,确保请求是用户主动发起":最常用的是 CSRF Token 验证,服务器在用户登录后生成随机 Token(如存于 Session 或 Cookie),并嵌入页面表单或请求头中;用户发起请求时需携带该 Token,服务器接收请求后验证 Token 是否与 Session 中的一致,不一致则拒绝请求 ------ 攻击者无法获取用户的 Token,伪造的请求因缺少有效 Token 会被拦截;其次可设置 SameSite Cookie 属性,将 Cookie 的SameSite设为StrictLax,限制 Cookie 仅在同源请求中发送,跨站请求无法携带 Cookie,从根源阻止 CSRF;关键操作(如转账、改密码)可增加验证码或二次验证(如输入支付密码),即使请求被伪造,也需用户主动完成验证才能执行;此外检查 Referer 字段(请求来源页面的 URL),仅允许同源 Referer 的请求,但若 Referer 被浏览器隐藏或篡改,需搭配其他措施使用。

XSS攻击是什么,怎么防范

XSS 攻击(跨站脚本攻击)是攻击者将恶意 JavaScript 脚本注入到目标网站的页面中,当用户访问该页面时,脚本在用户浏览器中执行,窃取用户 Cookie、劫持会话、伪造操作,甚至控制用户浏览器。根据注入方式可分三类:存储型(脚本存入数据库,如评论区注入,所有访问该页面的用户都会触发)、反射型(脚本通过 URL 参数注入,如搜索结果页,仅点击恶意 URL 的用户触发)、DOM 型(通过篡改页面 DOM 结构注入脚本,如通过document.write插入,无需后端参与)。

防范核心是 "阻止恶意脚本执行,隔离用户输入与页面代码":输入时,用工具类(如 Java 的HtmlUtils)过滤<script>onclick等危险标签 / 事件,比如将<转成<;存储到数据库前,确保特殊字符已转义。输出时,渲染页面 / 接口返回数据时,对用户输入的内容再次编码(如 Thymeleaf 默认会转义),避免直接拼接进 HTML。另外,后端设置 CSP 头(Content-Security-Policy: default-src 'self'),限制脚本只能从同源加载;敏感 Cookie 加HttpOnly属性,禁止 JS 读取。

前端的核心防护职责:聚焦 "输入校验" 与 "安全渲染"

前端的防护重点是在数据进入页面渲染前、以及用户输入时进行初步过滤,减少恶意脚本注入的可能性,同时提升用户体验(如实时输入反馈)。主要手段包括:

  1. 输入验证与过滤 :对用户输入的内容(如表单、评论、搜索框)做实时校验,过滤或拦截明显的恶意字符 / 脚本片段(如<script>onclickjavascript:等)。例如用户输入<script>alert('xss')</script>时,前端可直接提示 "输入包含非法字符",或自动移除<script>标签。
  2. 安全的 DOM 渲染 :避免使用风险较高的 DOM 操作方法(如innerHTMLouterHTML),优先使用textContentsetAttribute------ 前者会将内容当作纯文本解析,不会执行 HTML / 脚本。若必须用innerHTML,需先对内容进行 "HTML 编码"(将特殊字符如<转义为<>转义为>),让恶意脚本失去执行能力。
  3. 设置内容安全策略(CSP) :通过前端 HTTP 响应头(或<meta>标签)配置 CSP 规则,限制页面加载的资源来源(如只允许加载指定域名的脚本、图片),禁止执行内联脚本(如<script>标签内的代码、onclick事件)和eval()等危险函数,从根源上阻止恶意脚本执行。

后端的核心防护职责:聚焦 "数据校验" 与 "输出编码",做 "最后一道防线"

前端防护存在明显局限性(如用户可禁用 JS 绕过前端校验、通过抓包篡改请求数据),因此后端必须承担 "最终防护" 的责任,确保数据在存储、传输和返回时的安全性。主要手段包括:

  1. 严格的输入校验 :对前端传过来的所有数据(即使前端已校验)做二次校验,规则需比前端更严格(如限制输入长度、校验数据格式、过滤 HTML/JS 关键字)。例如后端接收评论内容时,强制移除scriptiframe等标签,或用成熟的库(如 Java 的 Jsoup、Python 的 bleach)对 HTML 内容进行安全清理。
  2. 输出编码:后端向页面返回数据时,根据数据的使用场景(如嵌入 HTML、JS、URL)进行对应的编码处理 ------ 例如嵌入 HTML 时做 "HTML 编码",嵌入 JS 时做 "JS 编码",确保数据被当作纯文本解析,而非可执行的代码。即使前端未做编码,后端的编码处理也能阻断恶意脚本执行。
  3. 设置 HttpOnly Cookie :将敏感 Cookie(如登录凭证sessionId)标记为HttpOnly,禁止前端通过 JS(如document.cookie)读取该 Cookie,避免 XSS 攻击通过脚本窃取 Cookie,这是防范 "会话劫持" 类 XSS 攻击的关键手段。
  4. 数据存储过滤:若数据需长期存储(如存入数据库),后端需先对数据进行清洗,移除或转义恶意内容 ------ 避免后续从数据库读取数据时,因未做防护导致 XSS(例如管理员后台读取恶意评论时触发脚本)。
DNS劫持是什么

NS 劫持是通过篡改 DNS 解析结果,让用户输入正常域名时,被引导到错误 IP 地址(如钓鱼网站、广告页面)的攻击方式。DNS 的作用是将域名转换为 IP,若解析过程被干预,就会导致 "域名与 IP 不匹配"。常见的劫持方式有三类:一是本地 DNS 劫持,攻击者通过恶意软件修改用户设备的本地 DNS 设置(如电脑的 hosts 文件、手机的 DNS 服务器地址),指向恶意 DNS 服务器;二是路由器 DNS 劫持,攻击者破解路由器管理员密码,修改路由器的 DNS 配置,让局域网内所有设备使用恶意 DNS;三是 DNS 服务器劫持,攻击者攻击公共 DNS 服务器(如 ISP 的 DNS),篡改其解析记录,导致大量用户受影响。

DNS 劫持的危害包括:用户访问钓鱼网站(如仿冒银行网站)导致账号密码泄露;被强制跳转至广告页面,影响使用体验;对外接口使用HTTPS ,即使 DNS 被劫持,后端配置 SSL 证书(如 Let's Encrypt),即使 DNS 被劫持,浏览器会因证书不匹配提示风险,阻止用户访问。

什么是跨域请求,什么是跨域限制

跨域请求是 "协议 / 域名 / 端口" 不同的请求。例如:http://a.com:8080页面请求https://a.com:8080(协议不同)、http://a.com请求http://b.com(域名不同)、http://a.com:80请求http://a.com:8080(端口不同),都属于跨域请求。

跨域限制是浏览器为保障安全,针对跨域请求施加的限制机制,也叫 "同源策略"。它的核心目的是防止恶意网站通过 JavaScript 获取其他网站的敏感数据(如 Cookie、LocalStorage、页面 DOM),避免用户信息泄露或被恶意操作。常见的跨域限制包括:无法读取跨域请求的响应数据(如XMLHttpRequestfetch发起跨域请求,若未配置 CORS,浏览器会拦截响应);无法操作跨域页面的 DOM(如iframe嵌入跨域页面,父页面无法获取子页面的document);默认情况下,跨域请求不会携带目标网站的 Cookie(需手动配置withCredentials且目标服务器允许)。

浏览器的限制是 "拦截响应" 而非 "阻止请求"------ 跨域请求会正常发送到目标服务器,服务器也会返回响应,但浏览器会检查响应是否符合 CORS(跨域资源共享)规则,不符合则丢弃响应,不交给前端代码处理。

网络场景

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

DNS 解析 :用户输入域名(如www.xxx.com)后,浏览器先查询本地 DNS 缓存,无结果则向运营商 DNS 服务器发起解析请求,最终获取域名对应的服务器 IP(后端需确保域名解析记录正确,如通过云服务商控制台配置 A 记录);

TCP 三次握手 :浏览器基于获取的 IP,与服务器的 80(HTTP)或 443(HTTPS)端口建立 TCP 连接,后端服务器(如 Nginx)在对应端口监听,完成三次握手后进入 ESTABLISHED 状态,准备接收请求;然后是HTTP 请求发送:浏览器封装 HTTP 请求(含请求行、请求头、空行,若为 POST 则带请求体),通过已建立的 TCP 连接发送给服务器,请求头会携带浏览器信息、Cookie(如登录态)、Accept 编码等;

后端处理请求:请求先到达接入层(如 Nginx),Nginx 通过负载均衡(如轮询)将请求转发到后端应用服务器(如 Tomcat、Spring Boot 服务);应用服务器接收后,先通过过滤器 / 拦截器(如登录校验、跨域处理),再匹配路由(如 Spring MVC 的 @RequestMapping),执行业务逻辑(如查询首页数据可能调用 Service 层,进而操作数据库或缓存);若需获取数据,会与 MySQL(查用户 / 商品信息)、Redis(查热点缓存)交互,组装响应数据;

HTTP 响应返回:应用服务器将处理结果封装为 HTTP 响应(含状态码 200、响应头 Content-Type: text/html、响应体 HTML 内容),通过 Nginx 返回给浏览器,若配置了 Gzip 压缩,后端会先压缩响应体以减少传输量;

TCP 四次挥手与浏览器渲染:响应完成后,若为短连接则触发四次挥手关闭 TCP 连接;浏览器接收 HTML 后,解析 DOM、加载 CSS/JS(JS 可能再次发起接口请求),最终渲染出首页 ------ 后端需确保 HTML 结构正确、静态资源(CSS/JS)路径配置无误,且通过 CDN 加速静态资源加载。

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

网络层排查:先确认客户端到服务器的网络是否通畅,比如让用户 ping 服务器 IP(看延迟 / 丢包)、traceroute 跟踪路由(看是否有节点拥堵);后端可通过云监控(如阿里云云监控)查看公网带宽使用情况,若带宽跑满(如超过购买的 100Mbps),会导致请求排队,需临时扩容或排查是否有异常流量(如爬虫、DDoS);

接入层排查:检查负载均衡(如 Nginx、云 LB)是否正常,比如查看 Nginx 日志(access.log)是否有大量 5xx 错误、请求等待时间(request_time)是否过长;若 Nginx 配置了限流(limit_req),需确认是否触发限流阈值,导致请求被拦截;同时检查 Nginx 与应用服务器的内网连接是否正常(如 telnet 应用服务器端口是否通);

应用层排查:这是后端核心排查点,先看应用服务器日志(如 Spring Boot 的 logs/xxx.log),重点关注慢请求(如接口耗时超过 500ms)、异常堆栈(如数据库连接超时、空指针);用监控工具(如 Prometheus+Grafana)查看接口 QPS、响应时间分布,定位耗时最长的接口;再看代码层面:是否有未优化的循环(如循环查数据库)、是否未用缓存(如首页数据每次都查 MySQL)、是否有锁竞争(如 synchronized 块导致线程阻塞);

数据层排查:数据库是常见瓶颈点,先查 MySQL 慢查询日志(slow_query_log),看是否有执行时间超过 1s 的 SQL(如未加索引的全表扫描,可通过 explain 分析 SQL 执行计划);检查数据库连接池状态(如 Spring Boot 的 HikariCP,看 activeConnections 是否达到 maxConnections,导致请求等待连接);Redis 方面,查看是否有大量慢命令(如 keys *)、缓存命中率是否过低(如低于 80%,导致频繁穿透到数据库);

服务器资源排查:登录应用服务器 / 数据库服务器,用 top 查看 CPU 使用率(若单个进程 CPU100%,可能是代码死循环)、内存使用率(若内存不足导致频繁 GC,用 jstat 查看 JVM GC 情况)、磁盘 IO(用 iostat 查看磁盘读写速度,若磁盘 IO 高,可能是日志写入过多或数据库表空间碎片多);若服务器资源耗尽,需临时扩容或优化资源占用(如清理日志、删除无用文件)。

server a和server b,如何判断两个服务器正常连接,出错怎么办

一、判断正常连接的方法

  1. 网络层连通性验证 :在 Server A 上执行ping ServerB的IP,若能收到回复(无丢包、延迟低,如 < 50ms),说明底层 IP 层连通;若 ping 不通,需进一步排查路由,但 ping 依赖 ICMP 协议,部分场景可能禁 ping,需结合其他方法;
  2. 端口可达性验证 :若 B 上运行服务(如 8080 端口的 API),在 A 上用telnet ServerB_IP 8080,若显示 "Connected to ServerB_IP",说明端口开放且可达;或用nc -zv ServerB_IP 8080(nc 工具更灵活,支持 TCP/UDP),返回 "succeeded!" 则端口正常;
  3. 应用层可用性验证 :这是最关键的验证(网络通不代表服务可用),若 B 提供 HTTP 接口(如/health健康检查接口),在 A 上用curl http://ServerB_IP:8080/health,若返回 200 状态码和 "UP" 信息,说明应用服务正常;若 B 是 MySQL 服务,在 A 上用mysql -h ServerB_IP -u 用户名 -p,能成功登录则服务正常。

二、出错后的排查步骤

  1. 先排查网络层问题
    • 若 ping 不通、telnet 失败:检查两台服务器是否在同一网段(如内网服务器需确认是否在同一 VPC);查看服务器防火墙规则(如 A 的 iptables 是否禁止出站到 B 的端口,B 的 iptables 是否禁止入站 A 的 IP,执行iptables -L -n查看);检查路由是否正常(执行route -n看是否有到对方 IP 的路由,或联系运维排查网关、交换机配置);
  2. 再排查服务层问题
    • 若 telnet 通但应用不可用(如 curl 返回 404/500):先登录 Server B,用netstat -tuln | grep 8080(或ss -tuln)确认服务是否在监听目标端口(若未监听,说明服务未启动,需查看 B 的应用日志,如tail -f /logs/xxx.log找启动失败原因,如端口被占用、配置文件错误);
    • 若服务已监听:检查 B 的应用是否正常(如 Spring Boot 服务用ps -ef | grep java看进程是否存在,若进程在但接口不通,可能是应用死锁或线程池满,用jstack 进程ID分析线程状态);
  3. 最后排查权限 / 配置问题
    • 若 A 调用 B 的接口需认证(如 Token、IP 白名单),检查 A 是否携带正确认证信息,B 是否将 A 的 IP 加入白名单;若 B 是数据库,检查 A 的 IP 是否在 MySQL 的 user 表中授权(执行select host,user from mysql.user;查看)。
服务器端正常启动了,但是客户端请求不到有哪些原因,如何排查

一、常见原因

  1. 网络层阻断:服务器端口未对外开放(如云服务器安全组未放通 80/443 端口)、防火墙拦截请求(如 iptables 禁止入站)、客户端与服务器网络不通(如跨网段无路由);
  2. 接入层配置错误:负载均衡(如 Nginx、云 LB)未绑定服务器 IP / 端口,或转发规则错误(如将 80 端口请求转发到不存在的 8081 端口)、Nginx 未启动或配置错误(如监听端口写错);
  3. 服务层问题 :服务虽启动但未监听正确 IP / 端口(如 Spring Boot 配置server.address=127.0.0.1,仅本地可访问,外部无法连接)、服务端口被占用(如另一进程占用 8080,服务虽启动但实际未监听成功)、服务启动后进入异常状态(如死锁、线程池满,无法处理新请求);
  4. 配置 / 权限问题:服务需认证(如 API 密钥、登录态),客户端未携带;服务配置 IP 白名单,客户端 IP 未在名单内;HTTPS 服务证书过期或配置错误,客户端访问被拒绝。

二、排查步骤

  1. 第一步:验证服务是否真的 "正常启动"
    • 登录服务器,用ps -ef | grep 服务进程名(如ps -ef | grep java)确认服务进程存在;
    • netstat -tuln | grep 服务端口(如grep 8080)确认服务在监听目标端口,且监听 IP 不是 127.0.0.1(若监听 127.0.0.1,需修改配置为 0.0.0.0,允许外部访问);
    • 本地测试服务:在服务器上用curl http://127.0.0.1:8080/health,若返回正常,说明服务本身没问题,问题在外部网络 / 接入层;若本地也不通,说明服务启动异常(查看日志找原因);
  2. 第二步:排查网络层是否通畅
    • 客户端 ping 服务器 IP,看是否能通(排除网络不通);
    • 客户端用telnet 服务器IP 服务端口nc -zv 服务器IP 服务端口,若不通,检查服务器安全组(如阿里云 ECS 安全组入站规则是否放通该端口)、防火墙(执行iptables -L -n看是否有REJECT该端口的规则,若有则用iptables -D INPUT -p tcp --dport 8080 -j REJECT删除);
  3. 第三步:排查接入层配置
    • 若用 Nginx,查看 Nginx 配置文件(如/etc/nginx/nginx.conf),确认proxy_pass是否指向正确的服务 IP: 端口(如proxy_pass http://127.0.0.1:8080;);
    • 查看 Nginx 日志(/var/log/nginx/access.logerror.log),若 access.log 无客户端请求记录,说明请求未到 Nginx(问题在 DNS / 负载均衡);若有记录但返回 502,说明 Nginx 到服务的连接失败(检查服务端口是否正确);
  4. 第四步:排查配置 / 权限问题若服务有 IP 白名单,检查客户端 IP 是否在白名单内(如 Spring Boot 的ip.whitelist配置);
    • 若为 HTTPS 服务,客户端访问时提示证书错误,检查服务器证书是否过期(用openssl x509 -in 证书文件 -noout -dates查看有效期),或是否配置了正确的证书路径(如 Nginx 的ssl_certificatessl_certificate_key)。
服务器ping不通,但是http能请求成功,什么原因造成的
  1. 服务器防火墙禁止 ICMP 协议 :这是最常见原因。服务器的 iptables 或云安全组配置了 "禁止 ICMP 请求"(即禁止 ping),但允许 TCP 80/443 端口的请求。例如:
    • Linux 服务器执行iptables -A INPUT -p icmp --icmp-type echo-request -j DROP,会丢弃所有 ping 请求(echo-request 是 ping 的请求包),但不影响 TCP 端口;
    • 云服务器(如阿里云、腾讯云)安全组默认可能只放通 80/443/22 端口,未放通 ICMP 协议,导致 ping 不通,但 HTTP 请求能通过 80/443 端口到达服务;
  2. 服务器内核参数禁用 ICMP 响应 :部分服务器通过内核参数关闭了 ICMP 响应,比如修改/proc/sys/net/ipv4/icmp_echo_ignore_all为 1(1 表示忽略所有 ICMP echo 请求),此时即使防火墙未拦截 ICMP,服务器也不会回复 ping 请求,但 TCP 服务不受影响;
  3. 网络中间设备阻断 ICMP:客户端到服务器的网络路径中,路由器、交换机或防火墙配置了 "阻断 ICMP 包",但允许 TCP 80/443 包。例如:企业内网防火墙禁止员工 ping 外网服务器,但允许 HTTP 访问;或 CDN 节点拦截了 ICMP 请求,但正常转发 HTTP 请求到源站;
  4. 服务器绑定的 IP 差异(特殊场景):若服务器有多个 IP(如内网 IP 和公网 IP),客户端 ping 的是其中一个 IP(如内网 IP),但 HTTP 请求用的是另一个 IP(如公网 IP),且内网 IP 的 ICMP 被阻断,公网 IP 的 TCP 端口正常。例如:客户端 ping 服务器内网 IP(192.168.1.100,ICMP 被禁),但通过公网 IP(203.0.113.100)访问 HTTP,导致 ping 不通但 HTTP 正常。
相关推荐
不是笨小孩i2 小时前
Websocket+cpolar:如何轻松实现服务远程访问?
网络·websocket·网络协议
Mr.Ja3 小时前
【关于虚拟机执行ip addr 命令不显示ip地址问题】
网络协议·tcp/ip·php
雨声不在3 小时前
cronet从编译到修改之: 支持IP直连
python·网络协议·tcp/ip·cronet
8K超高清3 小时前
汇世界迎全运 广州国际社区运动嘉年华举行,BOSMA博冠现场展示并分享与科技全运的故事
运维·服务器·网络·数据库·人工智能·科技
2503_924806853 小时前
动态IP的适用业务场景
网络·网络协议·tcp/ip
康一夏4 小时前
git fatal:Server aborted the SSL handshake
git·网络协议·ssl
weixin_446260854 小时前
提升开发效率的RPC系统!
网络·网络协议·rpc
黄豆匿zlib5 小时前
OpenSpeedy下载 - 全平台网盘提速加速工具|官网入口
网络·娱乐
jiunian_cn5 小时前
【Linux网络】TCP协议
linux·网络·tcp/ip