计算机网络各层协议
计算机网络各层协议
应用层常见的协议
HTTP(Hypertext Transfer Protocol,超文本传输协议)
主要是为 Web 浏览器与 Web 服务器之间的通信而设计的。客户端向服务器发送 HTTP Request(请求),服务器响应请求并返回 HTTP Response(响应)。
HTTP 协议基于 TCP 协议,发送 HTTP 请求之前首先要建立 TCP 连接也就是要经历 3 次握手。目前使用的 HTTP 协议大部分都是 1.1。在 1.1 的协议里面,默认是开启了 Keep-Alive 的,这样的话建立的连接就可以在多次请求中被复用了。
HTTP是有状态的吗
HTTP 协议是”无状态”的协议。断开 TCP 链接,下一次连接与上一次无关。为了识别不同的请求是否来自同一客户,引用 HTTP 会话机制,而维持这个会话则主要靠 session 和 cookie。
介绍一下cookie
服务器给浏览器颁发一个通行证cookie,这样服务器就能从cookie上确认浏览器身份了,cookie 实际上是一小段的文本信息,存储在客户端。web 服务器通过传送 HTTP 包头中的 set-Cookie 把一个 cookie 发送到用户的浏览器中,内容主要包括:名字,值,过期时间。 如果不设置过期时间,则表示这个 cookie 的生命期为浏览器会话期间,只要关闭浏览器窗口,cookie 就消失了,这种生命期为浏览器会话期的 cookie 被称为会话 cookie。会话 cookie 一般不存储在硬盘上而是保存在内存里;如果设置了过期时间,浏览器就会把 cookie 保存在硬盘上,关闭后再次打开浏览器,这些 cookie 仍然有效直到超过设定的过期时间。
介绍一下session
session存储在服务器端。 当客户端第一次请求服务端的时候,服务端会检查客户端的请求头携带的 cookie 中,是否包含 sessionID,如果有的话则会检索这个 sessionID 对应的 session 是否存在。如果不存在则会创建相应的会话信息,生成对应的 session,并将 sessionID返回给客户端,客户端接收到这个 seesionID,把它存储起来,下一次发送请求的时候,附带着这个 sessionID一起发送给服务端,服务端只要根据这个 sessionID,就知道是谁了。服务端可以给这个 sessionID 设置过期时间。
简单来说,cookie 机制采用的是在客户端保持状态的方案,而 session 机制采用的是在服务器保持状态的方案。Cookie不会占服务器资源,是存在客户端内存或者一个Cookie的文本文件中;而Session则会占用服务器资源。但是Cookies是保存在本机上的,其信息完全可见且本地易于编辑,往往可能引起很多安全问题,是不可靠的。Session是可靠的。但是目前很多著名站点都用Session。
介绍一下Token
Token(如JWT)存储在客户端,是一个加密的令牌,服务端通过一定的方式将用户的信息加密生成一个 JWT Token,后续客户端带着这个 token来访问服务端时,服务端可以解密得到对应的用户信息,这样就能进行身份和权限的验证了。可以跨多个会话使用。
简单来说,Cookie 和Session 更适合用于单次会话的认证和状态管理,而Token 更适合用于跨会话的认证和状态管理。
通过session登录状态的维持过程
- 首先用户在客户端浏览器发起登录请求
- 登录成功后,服务端会把用户信息保存在服务端,并返回一个唯一的 sessionID给客户端浏览器
- 客户端浏览器会把这个唯一的 sessionID保存在 cookie 中
- 以后再次访问 web 应用时,客户端浏览器会把这个唯一的 sessionID带上,这样服务端就能根据这个唯一标识找到用户信息
Cookie 被禁用怎么办?
利用 URL 重写,把 Session ID 直接附加在 URL 路径的后面。
Http2.0和Http3.0有什么区别?
- 传输协议:HTTP/2.0 是基于 TCP 协议实现的,HTTP/3.0 新增了QUIC协议来实现可靠传输,可以将 QUIC看作是 UDP 的升级版本,在其基础新增了很多功能比如加密、重传等等。
- 连接建立:HTTP/2.0需要经过经典的 TCP 三次握手过程(由于安全的HTTPS 连接建立还需要TLS 握手,共需要大约3个 RTT)。QUIC协议通过connectionID来表示链接,切换网络之后可以复用这个连接,连接建立仅需0-RTT。
- 队头阻塞问题:HTTP/2.0多请求复用一个 TCP 连接,一旦发生丢包,就会阻塞住所有的 HTTP请求。HTTP/3.0基于QUIC协议,一个连接建立多个不同的数据流,这些数据流之间独立互不影响,某个数据流发生丢包了,其数据流不受影响(本质上是多路复用+轮询)。
- 错误恢复:HTTP/3.0具有更好的错误恢复机制,当出现丢包、延迟等网络问题时,可以更快地进行恢复和重传。而HTTP/2.0则需要依赖于 TCP的错误恢复机制。
Http1.0和Http1.1有什么区别
- Http1.1新增了连接管理即 keepalive,支持长连接。
- 支持 pipeline,无需等待前面的请求响应,即可发送第二次请求。
- 允许响应数据分块。
- 新增更多的缓存控制策略
- 加入了 Host 头,允许在同一IP地址上托管多个域名,从而实现虚拟主机的功能,通过host头判断要访问哪个主机。
Http1.1和Http2.0有什么区别?
- 是二进制协议,不再是纯文本。
- 支持一个 TCP 连接发起多请求,移除了 pipeline。
- http1.1支持body压缩,不支持头部压缩;http2.0利用 HPACK 压缩头部,减少数据传输量。
- 允许服务端主动推送数据。
HTTP 和 HTTPS 有什么区别?
- 默认端口号:HTTP 默认是 80,HTTPS 默认是 443。
- URL 前缀:HTTP 的 URL 前缀是
http://
,HTTPS 的 URL 前缀是https://
。 - 安全性和资源消耗:HTTP 协议,客户是明文传输,并且客户端和服务器端都无法验证对方的身份。HTTPS 是运行在 SSL/TLS协议 之上的 HTTP 协议,并且需要通过数字证书来验证客户端和服务端的身份。传输内容经过加密,加密采用对称加密,但对称加密的密钥用服务器方的证书进行了非对称加密。所以说,HTTP 安全性没有 HTTPS 高,但是 HTTPS 比 HTTP 耗费更多服务器资源,页面响应速度会慢一些,
- SEO(搜索引擎优化):搜索引擎通常会更青睐使用 HTTPS 协议的网站,因为 HTTPS 能够提供更高的安全性和用户隐私保护。使用 HTTPS 协议的网站在搜索结果中可能会被优先显示,从而对 SEO 产生影响。
HTTP 状态码有哪些?
- 1xx Informational(信息性状态码)
101 Switching Protocol(协议切换)状态码表示服务器应客户端升级协议的请求对协议进行切换。
- 2xx Success(成功状态码)
- 200 OK:请求被成功处理。比如我们发送一个查询用户数据的 HTTP 请求到服务端,服务端正确返回了用户数据。这个是我们平时最常见的一个 HTTP 状态码。
- 201 Created:请求被成功处理并且在服务端创建了一个新的资源。比如我们通过 POST 请求创建一个新的用户。
- 202 Accepted:服务端已经接收到了请求,但是还未处理。
- 204 No Content:服务端已经成功处理了请求,但是没有返回任何内容。
- 3xx Redirection(重定向状态码)
- 301 Moved Permanently:资源被永久重定向了。比如你的网站的网址更换了。
- 302 Found:资源被临时重定向了。比如你的网站的某些资源被暂时转移到另外一个网址。
- 4xx Client Error(客户端错误状态码)
- 400 Bad Request:发送的 HTTP 请求存在问题。比如请求参数不合法、请求方法错误。
- 401 Unauthorized:未认证却请求需要认证之后才能访问的资源。
- 403 Forbidden:直接拒绝 HTTP 请求,不处理。一般用来针对非法请求。
- 404 Not Found:你请求的资源未在服务端找到。比如你请求某个用户的信息,服务端并没有找到指定的用户。
- 409 Conflict:表示请求的资源与服务端当前的状态存在冲突,请求无法被处理。
- 5xx Server Error(服务端错误状态码)
- 500 Internal Server Error:服务端出问题了(通常是服务端出 Bug 了)。比如你服务端处理请求的时候突然抛出异常,但是异常并未在服务端被正确处理。
- 502 Bad Gateway:我们的网关将请求转发到服务端,但是服务端返回的却是一个错误的响应。
GET 和 POST 的区别
GET 和 POST 是 HTTP 协议中两种常用的请求方法
- 语义(主要区别):GET 通常用于查询资源,而 POST 通常用于创建或修改资源。
- 幂等:GET 请求是幂等的,即多次重复执行不会改变资源的状态,而 POST 请求是不幂等的,即每次执行可能会产生不同的结果或影响资源的状态。
- 格式:GET 请求的参数通常放在 URL 中,形成查询字符串(querystring),而 POST 请求的参数通常放在请求体(body)中,可以有多种编码格式,如 application/x-www-form-urlencoded、multipart/form-data、application/json 等。GET 请求的 URL 长度受到浏览器和服务器的限制,而 POST 请求的 body 大小则没有明确的限制。不过,实际上 GET 请求也可以用 body 传输数据,只是并不推荐这样做,因为这样可能会导致一些兼容性或者语义上的问题。
- 缓存:由于 GET 请求是幂等的,它可以被浏览器或其他中间节点(如代理、网关)缓存起来,以提高性能和效率。而 POST 请求则不适合被缓存,因为它可能有副作用,每次执行可能需要实时的响应。
- 安全性:GET 请求和 POST 请求如果使用 HTTP 协议的话,那都不安全,因为 HTTP 协议本身是明文传输的,必须使用 HTTPS 协议来加密传输数据。另外,GET 请求相比 POST 请求更容易泄露敏感数据,因为 GET 请求的参数通常放在 URL 中。
Websocket:全双工通信协议
WebSocket 是一种基于 TCP 连接的全双工通信协议,即客户端和服务器可以同时发送和接收数据。
WebSocket用于弥补 HTTP 协议在持久通信能力上的不足。客户端和服务器仅需一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket 的常见应用场景:视频弹幕,实时消息推送,实时游戏对战,多用户协同编辑等等
WebSocket 的工作过程可以分为以下几个步骤:
- 客户端向服务器发送一个 HTTP 请求,请求头中包含
Upgrade: websocket
和Sec-WebSocket-Key
等字段,表示要求升级协议为 WebSocket; - 服务器收到这个请求后,会进行升级协议的操作,如果支持 WebSocket,它将回复一个 HTTP 101 状态码,响应头中包含 ,
Connection: Upgrade
和Sec-WebSocket-Accept: xxx
等字段、表示成功升级到 WebSocket 协议。 - 客户端和服务器之间建立了一个 WebSocket 连接,创建持久性的连接,并进行双向数据传输。进行双向的数据传输。数据以帧(frames)的形式进行传送,WebSocket 的每条消息可能会被切分成多个数据帧(最小单位)。发送端会将消息切割成多个帧发送给接收端,接收端接收消息帧,并将关联的帧重新组装成完整的消息。
- 客户端或服务器可以主动发送一个关闭帧,表示要断开连接。另一方收到后,也会回复一个关闭帧,然后双方关闭 TCP 连接。
另外,建立 WebSocket 连接之后,通过心跳机制来保持 WebSocket 连接的稳定性和活跃性。
应用层的心跳机制
基本方法就是在服务器端设置一个Timer事件,在一定时间段内向客户端一个心跳数据包,若在一定时间内没有收到客户端的回应,那么就会认为客户端掉线;同样客户端在一定时间段内没有收到服务器的心跳包,则判断与服务器端连接断开。
SMTP(Simple Mail Transfer Protocol,简单邮件发送协议)
基于 TCP 协议,是一种用于发送电子邮件的协议。
注意 ⚠️:SMTP 协议只负责邮件的发送,而不是接收。要从邮件服务器接收邮件,需要使用 POP3 或 IMAP 协议。
电子邮件的发送过程?
比如我的163邮箱,我要向qq邮箱发送邮件,整个过程可以简单分为下面几步:
- 通过 SMTP 协议,我将我写好的邮件交给 163 邮箱服务器(邮局)。
- 163 邮箱服务器发现我发送的邮箱是 qq 邮箱,然后它使用 SMTP 协议将我的邮件转发到 qq 邮箱服务器。
- qq 邮箱服务器接收邮件之后就通知用户来收邮件,然后用户就通过 POP3/IMAP 协议将邮件取出。
如何判断邮箱是真正存在的?
很多场景(比如邮件营销)下面我们需要判断我们要发送的邮箱地址是否真的存在,这个时候我们可以利用 SMTP 协议来检测:
- 通过邮箱域名、SMTP协议找到邮箱服务器地址
- 尝试与服务器建立连接
- 连接成功后尝试向需要验证的邮箱发送邮件
- 根据返回结果判定邮箱地址的真实性
POP3/IMAP(邮件接收协议)
基于 TCP 协议,两者都是负责邮件接收的协议。IMAP 协议是比 POP3 更新的协议,它在功能和性能上都更加强大。IMAP 支持邮件搜索、标记、分类、归档等高级功能,而且可以在多个设备之间同步邮件状态。几乎所有现代电子邮件客户端和服务器都支持 IMAP。
FTP(File Transfer Protocol,文件传输协议)
基于 TCP 协议,是一种用于在计算机之间传输文件的协议,可以屏蔽操作系统和文件存储方式。
FTP 是基于客户—服务器(C/S)模型而设计的,在客户端与 FTP 服务器之间建立两个连接。如果我们要基于 FTP 协议开发一个文件传输的软件的话,首先需要搞清楚 FTP 的原理。关于 FTP 的原理,很多书籍上已经描述的非常详细了:
FTP 的独特的优势同时也是与其它客户服务器程序最大的不同点就在于它在两台通信的主机之间使用了两条 TCP 连接(其它客户服务器应用程序一般只有一条 TCP 连接):
- 控制连接:用于传送控制信息(命令和响应)
- 数据连接:用于数据传送;
这种将命令和数据分开传送的思想大大提高了 FTP 的效率。

注意 ⚠️:FTP 是一种不安全的协议,因为它在传输过程中不会对数据进行加密。因此,FTP 传输的文件可能会被窃听或篡改。建议在传输敏感数据时使用更安全的协议,如 SFTP(一种基于 SSH 协议的安全文件传输协议,用于在网络上安全地传输文件)。
Telnet(远程登陆协议)
基于 TCP 协议,用于通过一个终端登陆到其他服务器。Telnet 协议的最大缺点之一是所有数据(包括用户名和密码)均以明文形式发送,这有潜在的安全风险。这就是为什么如今很少使用 Telnet,而是使用一种称为 SSH 的非常安全的网络传输协议的主要原因。
SSH(Secure Shell Protocol,安全的网络传输协议)
基于 TCP 协议,通过加密和认证机制实现安全的访问和文件传输等业务
DNS(Domain Name System,域名管理系统)
用于解决域名和 IP 地址的映射问题。
DNS 完整查询过程
- 首先搜索 浏览器的 DNS 缓存 ,缓存中维护一张域名与 IP 地址的对应表
- 如果没有命中,则继续搜索 操作系统的 DNS 缓存
- 如果依然没有命中,则操作系统将域名发送至 本地域名服务器 ,本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果(注意:主机和本地域名服务器之间的查询方式是 递归查询 )
- 若本地域名服务器的 DNS 缓存没有命中,首先本地域名服务器向根域名服务器发起请求,
- 根域名服务器告诉本地DNS,顶级域名服务器的地址
- 本地域名服务器拿到这个顶级域名服务器的地址后,获取权威域名服务器的地址
- 本地域名服务器根据权威域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
- 本地域名服务器 将得到的 IP 地址返回给操作系统,同时自己将 IP 地址 缓存 起来📝
- 操作系统 将 IP 地址返回给浏览器,同时自己也将 IP 地址 缓存 起来📝
至此, 浏览器 就得到了域名对应的 IP 地址
浏览器输入URL之后发生了什么【HTTP请求的全过程】
tip:URL 统一资源定位符 URI:统一资源标识符
- 浏览器首先会对URL进行解析,解析出协议、域名、端口号,还有可能的一些资源路径、参数
- DNS协议将域名转换为IP地址
- 浏览器获得了服务器IP,一般应用层的协议是HTTP/HTTPS/WS,浏览器会向服务器发起TCP连接,发生三次握手
- 建立连接后,就可以进行数据通信过程,浏览器会给服务器发送一个 HTTP 请求报文,请求报文包括请求行、请求头、请求体。
- 当服务器收到浏览器发送的请求报文后,服务器会对此请求报文进行相应的处理,并返回响应报文给浏览器。
- 浏览器收到服务器的响应报文后,从响应体中得到相应资源,如 文字、图片等,并进行渲染,然后将结果呈现给用户。
- 当数据返回浏览器后,根据请求/响应头中 Connection 的 Keep-Alive 属性可以选择是否断开 TCP 连接,如果不需要再进行数据通信,即可以关闭连接,此时则会发生四次挥手行为。
tip:浏览器为了提升性能,在 URL 解析之后,实际会先查询是否有缓存,如果缓存命中,则直接返回缓存资源。
如果是 HTTPS 协议,在建立 TCP 连接之后,还需要进行 SSL/TLS 握手过程,以协商出一个会话密钥,用于消息加密,提升安全性。
传输层有哪些常见的协议?
- TCP(Transmission Control Protocol,传输控制协议 ):提供 面向连接 的,可靠的数据传输服务。
- UDP(User Datagram Protocol,用户数据协议):提供 无连接 的,尽最大努力 的数据传输服务(不保证数据传输的可靠性),简单高效。
TCP和UDP的区别
- 是否面向连接:TCP是面向连接的协议,在传送数据之前必须先建立连接,数据传送结束后要释放连接。通过确认、重传、流量控制、拥塞控制等机制来保证可靠、有序的数据传输;UDP是无连接协议,不保证数据传输的可靠性。
- 传输效率:由于使用 TCP 进行传输的时候多了连接、确认、重传等机制,所以 TCP 的传输效率要比 UDP 低。
- 传输形式:TCP 是面向字节流的,UDP 是面向报文的。
- 首部开销:TCP 首部开销(20 ~ 60 字节)比 UDP 首部开销(8 字节)要大。
- 是否提供广播或多播服务:TCP 只支持点对点通信,UDP 支持一对一、一对多、多对一、多对多;
什么时候选择 TCP,什么时候选 UDP?
- UDP 用于对数据可靠性要求不高的场景,比如:看视频、直播等等。
- TCP 用于需要可靠传输的场景,比如文件传输、发送和接收邮件、远程登录等等。
什么是TCP中的拆包和粘包问题,有什么解决方案吗?
因为TCP是面向字节流的,不会保留发送时的数据边界,就有可能在接收方读取数据时出现拆包和粘包的问题。
一、拆包问题拆包问题是指一个完整的数据包被拆分成多个部分进行发送,接收方需要识别并重组这些分散的数据。解决方案:
- 添加长度头部:在每个数据包前添加一个固定长度的头部字段,用于表示数据包的总长度。接收方首先读取头部,了解数据包的长度,然后按需读取剩余部分。这种方法灵活性较高,适用于长度可变的数据包。
- 特殊分隔符:在数据包之间使用特定的分隔符来区分。接收方读取数据时检测分隔符,判断数据包的边界。这种方法适合文本协议,但需要保证分隔符不会出现在数据内容中。
二、粘包问题粘包问题是指多个数据包被合并为一个包进行发送,接收方需要拆分出完整的数据包。解决方案:
- 定时器:在发送方设置定时器,定时发送缓存区的数据,减少数据合并的可能性。
- 添加头部长度:通过读取头部信息判断一个完整的数据包长度,从而分离出各个数据包。
建立一个 TCP 连接需要“三次握手”,缺一不可
- 一次握手:客户端发送带有 SYN(SEQ=x) 标志的数据包 -> 服务端,然后客户端进入 SYN_SEND 状态,等待服务端的确认;
- 二次握手:服务端发送带有 SYN-ACK(SEQ=y,ACK=x+1) 标志的数据包 –> 客户端,然后服务端进SYN_RECV 状态;
- 三次握手 客户端再发送一个ACK确认消息给服务器,客户端和服务端都进入ESTABLISHED 状态,完成 TCP 三次握手。建立起一个可靠的TCP连接。
SYN超时了怎么处理?
也就是client发送 SYN 至 server 然后就挂了,此时server发送SYN+ACK 就一直得不到回复。
需要阶梯性重试。
在Linux 中就是默认重试5次,并且就是阶梯性的重试,间隔就是1S、2S、4S、8s、16S,再第五次发出之后还得等 32s 才能知道这次重试的结果,如果这五次重试都没有得到恢复,总共等63s 才能断开连接。
介绍一下SYN泛洪攻击
SYN 超时需要耗费服务端 63s的时间断开连接,也就说 63S内服务端需要保持这个资源,所以不法分子就可以构造出大量的client 向 server 发SYN但是不回应server。使得 server 的SYN队列耗尽,无法处理正常的连接请求。
解决方案:
- 减少服务端重试的次数
- 可以开启tcp_syncookies。SYN 队列满了之后TCP根据服务端的ip、端口、然后客户端的ip、端口,对方SYN的序号,时间戳等等作生成一个特殊的序号(即 cookie)发过去,如果对方是正常的 client 会把这个序号发回来,然后 server 根据这个序号来建立连接。
为什么要三次握手?
- 避免历史重复连接
在网络传输中,数据包的传输并不总是按照时间顺序发送到达目标主机,在网络拥堵等情况下,客户端连续发送多个SYN建立连接的报文时,可能会出现旧的SYN报文比最新的SYN报文先到达服务端。
服务端收到旧的SYN报文后会回复一个SYN + ACK报文给客户端。
客户端收到SYN + ACK报文后,根据自身的上下文判断这是一个历史连接(序列号过期或超时)还是新的连接,如果是历史连接,则第三次握手发送的报文是RST报文,以中止历史连接。如果不是历史连接,则第三次发送的报文是ACK报文,通信双方成功建立连接。
如果是两次握手的连接方式,就无法判断当前连接是否是历史连接。
- 如果只有"两次握手"的话,当客户端的SYN请求在网络中被阻塞时,客户端无法接收到服务器发送的ACK报文,因此会重新发送SYN。然而,由于没有第三次握手,服务器无法确定客户端是否收到了建立连接的ACK确认信号。因此,服务器只能在收到每个SYN请求后主动建立一个连接,这将导致服务器资源的浪费。
断开连接 四次挥手是啥
双方都有能力主动断开连接,比如当A向B发送了最后一个数据包后,会进过
第一次挥手:A向B发送一个FIN标志 seq=x的数据包给服务器端,用来关闭客户端到服务器的连接,然后进入FIN_WAIT_1
第二次挥手:B收到A发送的信息,发送一个ACK ack=x+1的数据包给A,进入CLOSE_WAIT状态,A进入FIN_WAIT_2状态
第三次挥手:B给A发送一个FIN seq=y的数据包,请求关闭连接,进入LAST_ACK状态
第四次挥手:A给B发送一个ACK seq=y+1的数据包。B收到这个就会进入CLOSE状态。A进入TIME_WAIT状态,需要等待2MSL时间
为什么要四次挥手?
因为 TCP是全双工协议,连接的双方都要关闭,每一方都向对方发送FIN 和回应ACK。这样的过程就是四次挥手了。
挥手一定需要四次吗?
不一定,因为如果断开连接发起方发送FIN,另一方接收到了,并且也刚好发送完了数据,那么就可以把第二次挥手和第三次挥手合在一起,也就是把FIN和ACK一起发送回断开连接发起方,这样一来就变成了三次挥手。
为什么第二次和第三次不合在一起
因为另一端可能还有数据没发完
为什么最后客户端要等待2MSL/为什么要用TIME-WAIT
因为第四次挥手的ACK消息可能会丢失,这个时候被动关闭方就会重发FIN消息,如果关闭在方2MSL时间内收到了FIN消息,就会重发ACK消息。防止被动关闭方没有收到ACK消息,而不断重发FIN消息。
MSL:一个片段在网络中的最大存活时间,就是一个发送和一个回复的最大时间。
等待2MSL会产生什么问题?
- 如果服务器主动关闭大量的连接,那么会出现大量的资源占用,需要等到 2MSL 才会释放资源。
- 如果是客户端主动关闭大量的连接,那么在 2MSL里面那些端口都是被占用的,端口只有65535个,如果端口耗尽了就无法发起新的连接了,不过这个概率比较低。
怎么解决这个问题?最好是客户端来主动关闭,毕竟服务器对接很多服务,资源比较宝贵。
TCP有什么作用?
TCP是传输控制协议,控制数据的可靠、按序传输,端和端之间的流量控制以及整个网络的拥塞控制。
TCP保证可靠传输【超级重点】
1、基于数据块传输
应用数据被分割成 TCP 认为最适合发送的数据块,再传输给网络层,数据块被称为报文段或段。
2、对失序数据包重新排序以及去重
TCP 为了保证不发生丢包,就给每个包一个序列号,有了序列号能够将接收到的数据根据序列号排序,并且去掉重复序列号的数据就可以实现数据包去重。
3、校验和
TCP 将保持一个首部和数据的检验和。这是一个端到端的检验和,目的是如果收到段的检验和有差错,TCP 将丢弃这个报文段和不确认收到此报文段。
介绍一下TCP中的重传机制
TCP需要保证数据的可靠传输,需要接收方通过序列号来确认应答;如果数据丢失了,就需要重传机制。
- 超时重传
就是在发送数据时,设定一个定时器,当超过指定的时间后,没有收到对方的ACK确认应答报文,就会重发该数据,也就是我们常说的超时重传。
超时时间应该设置为多少?
RTT 指的是数据发送时刻到接收到确认的时刻的差值,也就是包的往返时间。
超时重传时间是以表示,一般略大于RTT。
如果超时重发的数据,再次超时又需要重传的时候,TCP 的策略是超时间隔加倍。两次超时,就说明网络环境差,不宜频繁反复发送。
超时重传存在的问题是,超时周期可能相对较长;如果网络状况良好,可以用「快速重传」机制来解决超时重发的时间等待。
- 快速重传
当发送方收到三个相同的 ACK 报文时,会在定时器过期之前,重传丢失的报文段。
快速重传机制只解决了一个重传时间较长的问题,但是它依然面临着另外一个问题。就是重传的时候,是重传一个,还是重传所有的问题。为了解决这个问题,于是就有 SACK 方法。
- SACK 方法
选择性确认。这种方式需要在 TCP 头部「选项」字段里加上 SACK 数据,它可以将已收到的数据的信息发送给「发送方」,这样发送方就可以知道哪些数据收到了,哪些数据没收到,知道了这些信息,就可以只重传丢失的数据。
- D-SACK方法
使用SACK告诉发送方哪些数据被重复接收了。【数据重复接收发生的情况:1、接收方的ACK丢失,发送方重传了接收方已经收到的数据;2、接收方设置的超时时间有点短;3、包乱序到达,先发的包后到。】
滑动窗口的作用是什么?
如果TCP每发送一个数据,都要进行接收方的一次应答。这样的话一次数据往返时间越长,通信效率就越低。因此TCP引入了窗口和累计应答这个概念,就是一次可以连续发送多个tcp段,接收方对这多个tcp段累计确认。
1) TCP 发送窗口可以划分成四个部分
- 已经发送并且确认的 TCP 段(已经发送并确认);
- 已经发送但是没有确认的 TCP 段(已经发送未确认);
- 未发送但是接收方准备接收的 TCP 段(可以发送);
- 未发送并且接收方也并未准备接受的 TCP 段(不可发送)。
TCP 发送窗口结构图示:

程序如何表示发送方的四个部分:
- SND.WND:发送窗口的大小【由接收方去欸的那个】
- SND.UNA:绝对指针,指向发送窗口的第一个字节。
- SND.NXT:绝对指针,指向未发送但可发送范围的第一个字节,也就是第三部分的第一个字节
可用窗口【未发送但可发送】大小 = SND.WND -(SND.NXT-SND.UNA)
。
2) TCP 接收窗口可以划分成三个部分
- 已经接收并且已经确认的 TCP 段(已经接收并确认);
- 等待接收且允许发送方发送 TCP 段(可以接收未确认);
- 不可接收且不允许发送方发送 TCP 段(不可接收)。
TCP 接收窗口结构图示:

程序如何表示接收方的三个部分:
- RCV.WND:接收窗口的大小【会通告给发送方、第二个部分的大小】
- RCV.NXT:指向期望从发送方发送来的下一个数据字节的序列号,也就是第二部分的第一个字节。
接收窗口的大小是约等于发送窗口的大小的。
因为滑动窗口并不是一成不变的。比如,当接收方的应用进程读取数据的速度非常快的话,这样的话接收窗口可以很快的就空缺出来。那么新的接收窗口大小,是通过 TCP 报文中的 Windows 字段来告诉发送方。那么这个传输过程是存在时延的,所以接收窗口和发送窗口是约等于的关系。
6、流量控制
让发送方根据接收方的实际接受能力,控制发送的数据量。
滑动窗口中我们假设发送和接收窗口是不变的,但是实际上,发送窗口和接收窗口中所存放的字节数,都是放在操作系统内存缓冲区中的,会被操作系统调整。
【第一个例子:服务端非常繁忙,应用层不能及时读取客户端发送的数据,接收窗口和发送窗口都减少为0,发生窗口关闭。发送方实际上会定时发送窗口探测报文,以便知道接收方的窗口是否发生了改变。】
【第二个例子:服务端系统资源非常紧张的时候,操作系统可能会直接减少缓冲区的大小,这个时候发送方不能及时知道这个消息,就可能发生数据包丢失的现象】为了防止这种情况发生,TCP 规定是不允许同时减少缓存又收缩窗口的,而是采用先收缩窗口,过段时间再减少缓存,这样就可以避免了丢包情况。
- 窗口关闭
如果窗口大小为 0 时,就会阻止发送方给接收方传递数据,直到窗口变为非 0 为止,这就是窗口关闭。
窗口关闭的潜在危险
当发生窗口关闭时,接收方处理完数据后,会向发送方通告一个窗口非 0 的 ACK 报文,如果这个通告窗口的 ACK 报文在网络中丢失了,那麻烦就大了。
这会导致发送方一直等待接收方的非 0 窗口通知,接收方也一直等待发送方的数据,如不采取措施,这种相互等待的过程,会造成了死锁的现象。
如何解决这个潜在危险?
TCP 为每个连接设有一个持续定时器,只要 TCP 连接一方收到对方的零窗口通知,就启动持续计时器。如果持续计时器超时,就会发送窗口探测 ( Window probe ) 报文,接收方收到这个探测报文后,会给出自己现在的接收窗口大小。
- 如果接收窗口仍然为 0,那么收到这个报文的一方就会重新启动持续计时器;
- 如果接收窗口不是 0,那么死锁的局面就可以被打破了。
窗口探测的次数一般为 3 次,每次大约 30-60 秒(不同的实现可能会不一样)。如果 3 次过后接收窗口还是 0 的话,有的 TCP 实现就会发 RST 报文来中断连接。
糊涂窗口综合征
如果接收方太忙了,来不及取走接收窗口里的数据,那么就会导致发送方的发送窗口越来越小。到最后,如果接收方腾出几个字节并告诉发送方现在有几个字节的窗口,而发送方会义无反顾地发送这几个字节,这就是糊涂窗口综合症。
糊涂窗口综合症的现象是可以发生在发送方和接收方:
- 接收方可以通告一个小的窗口
- 而发送方可以发送小数据
于是,要解决糊涂窗口综合症,就要同时解决上面两个问题就可以了:
- 让接收方不通告小窗口给发送方
- 让发送方避免发送小数据
1)怎么让接收方不通告小窗口呢?
MSS:最大分段大小
当「接收方窗口大小」小于 min( MSS,缓存空间/2 ) ,也就是小于 MSS 与 1/2 缓存大小中的最小值时,就会向发送方通告窗口为 0,也就阻止了发送方再发数据过来。
等到接收方处理了一些数据后,窗口大小 >= MSS,或者接收方缓存空间有一半可以使用,就可以把窗口打开让发送方发送数据过来。
2)怎么让发送方避免发送小数据呢?
发送方通常的策略如下:
使用 Nagle 算法,该算法的思路是延时处理,只有满足下面两个条件中的任意一个条件,才可以发送数据:
- 条件一:要等到窗口大小 >= MSS 并且 数据大小 >= MSS;
- 条件二:收到之前发送数据的 ack 回包;
只要上面两个条件都不满足,发送方就会囤积数据,直到满足上面的发送条件。
如果只满足发送方,接收方仍然桶盖小窗口,达到条件二,Nagle算法仍然会让发送方发送小数据。因此接收方得满足「不通告小窗口给发送方」+ 发送方开启 Nagle 算法,才能避免糊涂窗口综合症。
已经有了滑动窗口为什么还要拥塞控制?
流量控制管理的只是两端的情况。除此之外,还需要知道一下整体的网络情况,和整体网络情况适配,数据传输才会更顺利。
说说拥塞控制的步骤
TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量,拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送窗口为拥塞窗口和接收窗口中较小的一个。
那么怎么知道当前网络是否出现了拥塞呢?
其实只要「发送方」没有在规定时间内接收到 ACK 应答报文,也就是发生了超时重传,就会认为网络出现了拥塞。
TCP 的拥塞控制采用了四种算法,即 慢开始、 拥塞避免、快重传 和 快恢复。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。
- 慢开始: 慢开始算法的思路是当主机开始发送数据时,因为现在还不知道网络的情况,先探测一下,cwnd 从1开始,每经过一个传播轮次,cwnd 加倍。有一个叫慢启动门限 ssthresh (slow start threshold)状态变量。当 cwnd >= ssthresh 时,就会使用「拥塞避免算法」。
- **拥塞避免:**每经过一个往返时间 RTT 就把发送方的 cwnd 加 1,线性增长
这样发送窗口一直增长,网络就会慢慢出现拥塞、丢包的情况,这个时候需要对丢失数据包进行重传,也就进入了拥塞发生算法。
发生超时重传的拥塞发生算法
当发生了「超时重传」,则就会使用拥塞发生算法。【这样做的目的是迅速减少主机发送到网络中的分组数,使得发送拥塞的路由器有足够的时间把队列中积压的分组处理完毕。】
这个时候,ssthresh 和 cwnd 的值会发生变化:
- ssthresh 设为 cwnd/2,
- cwnd 重置为 1 (是恢复为 cwnd 初始化值,我这里假定 cwnd 初始化值 1)
再开始慢启动+拥塞避免算法。
发生快速重传的拥塞发生算法
前面超时重传的拥塞处理方法,会突然减少数据流,这种方法比较激进。所以可以使用快速重传算法。当接收方发现丢了一个数据包的时候,发送三次前一个包的 ACK,于是发送端就会快速地重传,不必等待超时再重传。
TCP 认为这种情况不严重,因为大部分没丢,只丢了一小部分,则 ssthresh 和 cwnd 变化如下:
- cwnd = cwnd/2 ,也就是设置为原来的一半;
- ssthresh = cwnd;
- 进入快速恢复算法
进入快速恢复算法如下:
- 拥塞窗口 cwnd = ssthresh + 3 ( 3 的意思是确认有 3 个数据包被收到了);
- 重传丢失的数据包;
- 如果再收到重复的 ACK,那么 cwnd 增加 1;
- 如果收到新数据的 ACK 后,把 cwnd 设置为第一步中的 ssthresh 的值,原因是该 ACK 确认了新的数据,说明从 duplicated ACK 时的数据都已收到,该恢复过程已经结束,可以回到恢复之前的状态了,也即再次进入拥塞避免状态;
快速恢复算法的变化过程如下图:

也就是拥塞窗口没有像「超时重传」一夜回到解放前,而是还在比较高的值,后续呈线性增长。
网络层有哪些常见的协议?
IP(Internet Protocol,网际协议)
TCP/IP 协议中最重要的协议之一,属于网络层的协议,主要作用是定义数据包的格式、对数据包进行路由和寻址,以便它们可以跨网络传播并到达正确的目的地。目前 IP 协议主要分为两种,一种是过去的 IPv4,另一种是较新的 IPv6,目前这两种协议都在使用,但后者已经被提议来取代前者。
ARP(Address Resolution Protocol,地址解析协议)
网络层与数据链路层有什么关系呢?
MAC 的作用则是实现「直连」的两个设备之间通信,而 IP 则负责在「没有直连」的两个网络之间进行通信传输。
ARP协议将IP 地址转换为 MAC地址,因为最终需要找到 MAC地址才能跟具体的设备通信。
ARP协议的工作原理
- 获取目标设备的IP地址,检查自己的ARP缓存表,如果查到了对应的MAC地址,直接发送数据包。
- 如果没有,会广播发送 ARP 请求,请求包中包含了想要知道MAC 地址的主机 IP 地址。
- 当同个链路中的所有设备收到 ARP 请求时,会看 ARP 请求包中的目标 IP 地址与自己的 IP 地址一致,那么这个设备就将自己的 MAC 地址放入ARP 响应包返回给主机。
- 主机收到了ARP响应,会将目标IP和对应的MAC地址写入自己的ARP缓存中。
RARP协议是什么?
RARP 用于将MAC地址转换为IP 地址,比如一些设备启动的时候,需要根据 RARP 来得知分配给它的ip是什么。
NAT(Network Address Translation,网络地址转换协议)
IPv4 的地址是非常紧缺的,在前面我们也提到可以通过无分类地址来减缓 IPv4 地址耗尽的速度,但是互联网的用户增速是非常惊人的,所以 IPv4 地址依然有被耗尽的危险。
于是,提出了一种网络地址转换 NAT 的方法,再次缓解了 IPv4 地址耗尽的问题。NAT 就是同个公司、家庭、教室内的主机对外部通信时,把私有 IP 地址转换成公有 IP 地址。

图中有两个客户端 192.168.1.10 和 192.168.1.11 同时与服务器 183.232.231.172 进行通信,并且这两个客户端的本地端口都是 1025。
此时,两个私有 IP 地址都转换 IP 地址为公有地址 120.229.175.121,但是以不同的端口号作为区分。
于是,生成一个 NAT 路由器的转换表,就可以正确地转换地址跟端口的组合,令客户端 A、B 能同时与服务器之间进行通信。
NAT 那么牛逼,难道就没缺点了吗?
由于 NAT依赖于自己的转换表,因此会有以下的问题:
- 外部无法主动与 NAT 内部服务器建立连接,因为 NAPT 转换表没有转换记录。
- 转换表的生成与转换操作都会产生性能开销。
- 通信过程中,如果 NAT 路由器重启了,所有的 TCP 连接都将被重置。
如何解决 NAT 潜在的问题呢?
解决的方法主要有两种方法。
第一种就是改用 IPv6
IPv6 可用范围非常大,以至于每台设备都可以配置一个公有 IP 地址,就不搞那么多花里胡哨的地址转换了,但是 IPv6 普及速度还需要一些时间。
第二种 NAT 穿透技术
NAT 穿越技术拥有这样的功能,它能够让网络应用程序主动发现自己位于 NAT 设备之后,并且会主动获得 NAT 设备的公有 IP,并为自己建立端口映射条目,
ICMP【互联网控制报文协议】
ICMP 功能都有啥?
确认 IP 包是否成功送达目标地址、报告发送过程中 IP 包被废弃的原因
在 IP 通信中如果某个 IP 包因为某种原因未能达到目标地址,那么这个具体的原因将由 ICMP 负责通知。
ICMP 类型
ICMP 大致可以分为两大类:
- 一类是用于诊断的查询消息,也就是「查询报文类型」
- 另一类是通知出错原因的错误消息,也就是「差错报文类型」

网关协议
内部网关协议IGP【用于在同一网络内部的路由器之间传播路由信息】
1、OSPF(Open Shortest Path First,开放式最短路径优先) )
内部网关协议,也是广泛使用的一种动态路由协议,基于链路状态算法,考虑了链路的带宽、延迟等因素来选择最佳路径。
2、RIP(Routing Information Protocol,路由信息协议)
内部网关协议,也是一种动态路由协议,基于距离向量算法,使用固定的跳数作为度量标准,选择跳数最少的路径作为最佳路径。
外部网关协议EGP【 在不同自治系统之间使用,用于在不同的网络域之间交换路由信息 】
3、BGP(Border Gateway Protocol,边界网关协议)
基于路径矢量算法。用于在互联网不同自治系统之间传递路由信息。
数据链路层常见的协议
自动重传请求(Automatic Repeat-reQuest,ARQ)ARQ协议是 OSI 模型中数据链路层和传输层的错误纠正协议之一。
停止等待 ARQ 协议
停止等待协议是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认(回复 ACK)。如果过了一段时间(超时时间后),还是没有收到 ACK 确认,说明没有发送成功,需要重新发送,直到收到确认后再发下一个分组;
在停止等待协议中,若接收方收到重复分组,就丢弃该分组,但同时还要发送确认。
1) 无差错情况:
发送方发送分组,接收方在规定时间内收到,并且回复确认.发送方再次发送。
2) 出现差错情况(超时重传):
停止等待协议中超时重传是指只要超过一段时间仍然没有收到确认,就重传前面发送过的分组(认为刚才发送过的分组丢失了)。因此每发送完一个分组需要设置一个超时计时器,其重传时间应比数据在分组传输的平均往返时间更长一些。这种自动重传方式常称为 自动重传请求 ARQ 。另外在停止等待协议中若收到重复分组,就丢弃该分组,但同时还要发送确认。
3) 确认丢失和确认迟到
- 确认丢失:确认消息在传输过程丢失。当 A 发送 M1 消息,B 收到后,B 向 A 发送了一个 M1 确认消息,但却在传输过程中丢失。而 A 并不知道,在超时计时过后,A 重传 M1 消息,B 再次收到该消息后采取以下两点措施:1. 丢弃这个重复的 M1 消息,不向上层交付。 2. 向 A 发送确认消息。(不会认为已经发送过了,就不再发送。A 能重传,就证明 B 的确认消息丢失)。
- 确认迟到:确认消息在传输过程中迟到。A 发送 M1 消息,B 收到并发送确认。在超时时间内没有收到确认消息,A 重传 M1 消息,B 仍然收到并继续发送确认消息(B 收到了 2 份 M1)。此时 A 收到了 B 第二次发送的确认消息。接着发送其他数据。过了一会,A 收到了 B 第一次发送的对 M1 的确认消息(A 也收到了 2 份确认消息)。处理如下:1. A 收到重复的确认后,直接丢弃。2. B 收到重复的 M1 后,也直接丢弃重复的 M1。
连续 ARQ 协议
连续 ARQ 协议可提高信道利用率。发送方维持一个发送窗口,凡位于发送窗口内的分组可以连续发送出去,而不需要等待对方确认。接收方一般采用累计确认,对按序到达的最后一个分组发送确认,表明到这个分组为止的所有分组都已经正确收到了。
- 优点: 信道利用率高,容易实现,即使确认丢失,也不必重传。
- 缺点: 不能向发送方反映出接收方已经正确收到的所有分组的信息。 比如:发送方发送了 5 条 消息,中间第三条丢失(3 号),这时接收方只能对前两个发送确认。发送方无法知道后三个分组的下落,而只好把后三个全部重传一次。这也叫 Go-Back-N(回退 N),表示需要退回来重传已经发送过的 N 个消息。
ping 的工作原理
ICMP协议是IP层的附属协议,是介于IP层和TCP层之间的协议,一般认为属于IP层协议。
ping用于检测目标主机可不可达。它是基于ICMP协议工作的,使用了 ICMP 里面的 ECHO REQUEST(类型为 8)和 ECHO REPLY(类型为 0)。假设机器A ping 机器B,工作过程如下:
- ping通知系统,新建一个固定格式的ICMP回送请求数据包ECHO REQUEST
- 由ICMP协议将该数据包和目标机器B的IP地址打包,一起转交给IP协议层。IP 层将以B的IP地址作为目的地址,本机 IP 地址作为源地址,协议字段设置为
1
表示是ICMP
协议,再加上一些其他控制信息,构建一个IP
数据包。 - 接下来,需要加入
MAC
头。如果在本地 ARP 映射表中查找出 B的IP 地址所对应的 MAC 地址,则可以直接使用;如果没有,则需要发送ARP
协议查询 MAC 地址。获得 MAC 地址后,由数据链路层构建一个数据帧;还要附加上一些控制信息,依据以太网的介质访问规则,将它们传送出去。 - 主机
B
收到这个数据帧后,先检查它的目的 MAC 地址,并和本机的 MAC 地址对比,如符合,则接收,否则就丢弃。 - 接收后检查该数据帧,将 IP 数据包从帧中提取出来,交给本机的 IP 层。同样,IP 层检查后,将有用的信息提取后交给 ICMP 协议。
- 主机
B
会构建一个 ICMP 回送响应消息数据包,再发回给给源主机。
在规定的时候间内,源主机如果没有接到 ICMP 的应答包,则说明目标主机不可达;如果接收到了 ICMP 回送响应消息,则说明目标主机可达。
此时,源主机会计算ICMP 数据包的往返时间
最终显示结果有这几项:发送到目的主机的IP地址、发送 & 收到 & 丢失的分组数、往返时间的最小、最大& 平均值