2

OSI七层模型 和 TCP/IP五层模型

物联网淑惠试用

  • 应用层:通过不同的应用层协议为不同的网络应用提供服务。
  • 表示层:使通信的应用程序能够解释交换数据的含义。
  • 会话层:负责建立、管理和终止表示层实体之间的通信会话。
  • 传输层:为两台主机进程之间的通信提供服务,建立端到端的连接。
  • 网络层:选择合适的路由和 IP 选址,确保数据按时成功传送。
  • 链路层:将网络层交下来的 IP 数据报组装成帧,在两个相邻节点间的链路上传送帧。
  • 物理层:实现计算机节点之间比特流的透明传送,尽可能屏蔽掉具体传输介质和物理设备的差异。

应用层、传输层、网络层常见协议

  • 应用层
    • HTTP:超文本传输协议,是一个简单的请求-响应协议,它通常运行在 TCP 之上。
    • DNS (Domain Name System) :域名系统,用于解析域名与IP地址。
    • FTP (File Transfer Protocol) :文件传输协议,是 TCP/IP 协议组中的协议之一。
    • SMTP:提供可靠且有效的电子邮件传输的协议。SMTP 是建立在 FTP 上的一种邮件服务,主要用于系统之间的邮件信息传递,并提供有关来信的通知。
    • SSL (Secure Sockets Layer) :安全套接字协议。在传输层对网络连接进行加密。
  • 传输层
    • TCP (Transmission Control Protocol) :传输控制协议。面向连接的、可靠的、基于字节流的。
    • UDP (User Datagram Protocol) :用户数据报协议。无连接。
  • 网络层
    • IP (Internet Protocol) :网络互联协议。负责分配IP地址,提供路由。
    • ARP (Address Resolution Protocol) :地址解析协议。将IP地址转换为物理地址。
    • ICMP (Internet Control Message Protocol) :Internet控制报文协议。在IP数据报传输的过程中进行差错报告和查询,比如网络通不通、主机是否可达。

哪些应用层协议使用了TCP,哪些使用了UDP?

上面列举的常用应用层协议中,只有 DNS 使用的是 UDP。因为用DNS域名解析时间更短~

应用层

HTTP常用头部信息

请求头部(Request)
  1. HTTP请求方式:主要用到 get 和 post。
  2. Host:请求的web服务器域名地址。
  3. User-Agent:浏览器信息。
  4. Accept:代表客户端希望接受的数据类型(text/html,image/png)
  5. Accept-Encoding:代表客户端能支持的内容压缩编码类型。
  6. Accept-Language:代表客户端用来展示返回信息的优先语言
  7. Connection:如果是 Keep-Ailve,表示需要长连接。
  8. cookie:HTTP请求发送时,会把保存在该请求域名下的所有 cookie 值一起发送给web服务器。
  9. Referer:请求资源的完整 URL
响应头部(Response)
  1. 响应状态:例如 HTTP/1.1 200 OK
  2. Date:服务端发送资源时的时间
  3. Location:表示重定向后的 URL
  4. Server:告知客户端服务器信息
  5. ETag:唯一标识分配的资源
实体头部
  1. Content-encoding:返回内容的编码
  2. Content-Length:返回内容的字节长度
  3. Content-Language:响应体的语言

Http的几种请求方法是什么?

  • GET方法:发送一个请求来取得服务器上的资源
  • POST方法:向URL指定的资源提交数据
  • PUT方法:跟POST方法很像,也是向服务器提交数据。put方法是幂等方法,在请求时容易造成数据冗余。
  • HEAD方法:只请求页面的首部
  • DELETE方法:删除服务器上的资源
  • OPTIONS方法:它用于获取当前URL所支持的方法。如果请求成功,会有一个Allow的头包含类似“GET,POST”这样的信息

post与get的区别

  1. GET 参数通过URL传递,并且请求参数会直接暴露在 URL 中,保留在浏览器记录里,可能存在安全问题。

    POST 参数放在请求实体中,并且参数不会被保留。

  2. GET 只支持 URL 编码,POST 支持多种编码格式。好 —> %E5%A5%BD
  3. GET 只支持 ASCII 字符格式的参数,而 POST 没有限制。
  4. GET 提交的数据大小有限制,而 POST 没有限制。
  5. GET 方法产生一个 TCP 数据包,POST 方法产生两个

HTTP状态码?

  • 2 开头的表示成功

    • 一般就是200
  • 3 开头的表示重定向

    • 301永久重定向
    • 302临时重定向
  • 4 开头的表示客户端错误

    • 403 禁止访问
    • 404 请求资源不存在
  • 5 开头的表示服务端错误

    • 500 执行请求时发生错误
    • 501 服务器不支持当前请求所需要的某个功能
    • 502 错误网关
    • 503 服务器处于超负荷状态或停机维护

状态码 301 和 302 的区别?

301:永久移动。请求浏览器是会缓存的,例如http:// 永久重定向到 https://

302:临时移动。例如未登陆的用户访问用户中心会重定向到登录页面,redirect标识302。

Cookie和Session的作用以及区别?

Cookie和Session的作用:

客户端和服务器进行交互使用了HTTP协议,但是HTTP协议是无状态的。但是在有些时候是需要保存一些客户端的请求信息,识别客户端的某些状态等。就需要用到Cooike和Session了。

区别
  1. cookie数据保存在客户端,session数据保存在服务器端。
  2. cookie放在别人那,安全性不高。为了提升安全性,可以在客户端加密,服务端解密。
  3. 当访问量增多时,session会占用服务器的性能。
  4. 单个cookie在客户端的限制是3k,session没有大小限制。
  5. cookie仅支持ASICC码,中文需要转化才能传输;session支持任意格式
  6. 因此,登陆信息等重要信息存放为session;其他信息要保留存放为cookie。

HTTP的长连接和短连接

  • 在HTTP/1.0中默认使用短连接。即 客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束后就中断连接。
  • 而从HTTP/1.1起,默认使用长连接。在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,我们可以设置参数来配置。
  • Keep-Alive 并不是没有缺点的,当长时间的保持 TCP 连接时容易导致系统资源被无效占用,若对 Keep-Alive 模式配置不当,将有可能比非 Keep-Alive 模式带来的损失更大。
使用场景
  • 长连接:多用于操作频繁,点对点的通讯,而且客户端连接数目较少的情况。例如:即时通信、网络游戏等。
  • 短连接:用户数目较多的Web网站一般用短连接,例如淘宝京东等。若采用长连接势必会使得服务端大量的资源被无效占用。

HTTPS的工作方式(建立连接的过程)

HTTPS 是以安全为目标的 HTTP 协议,在 HTTP 的基础上通过传输加密身份认证的方式保证了传输过程的安全性。其工作流程如下:

  1. 客户端发起一个 HTTPS 请求,并连接到服务器的 443 端口,发送的信息主要包括自身所支持的算法列表和密钥长度等;
  2. 服务端选择一种支持的加密算法,然后将它和其它密钥组件一同发送给客户端。
  3. 服务器向客户端发送一个包含数字证书(CA)的报文,该数字证书中包含证书的颁发机构、过期时间、服务端的公钥等信息。
  4. 最后服务端发送一个完成报文通知客户端 SSL 的第一阶段已经协商完成。
  5. SSL 第一次协商完成后,客户端发送一个回应报文,报文中包含一个随机密码串,并使用证书公钥加密。
  6. 紧接着客户端会发送一个报文提示服务端在此之后的报文都是加密的。
  7. 客户端向服务端发送一个 finish 报文,这次握手中包含第一次握手至今所有报文的整体校验值,最终协商是否完成取决于服务端能否成功解密。
  8. 服务端同样发送加密后的报文,让客户端进行确定。最后发送 finish 报文告诉客户端自己能够正确的解密报文。

当服务端和客户端的 finish 报文交换完成之后,SSL 连接就算建立完成了,之后就进行和 HTTP 相同的通信过程,唯一不同的是在 HTTP 通信过程中并不是采用明文传输,而是采用对称加密的方式,其中对称密钥已经在 SSL 的建立过程中协商好了。

HTTP和HTTPS的区别

  • HTTP 协议以明文方式发送内容,数据都是未加密的,安全性较差。HTTPS 数据传输过程是加密的,安全性较好。
  • 端口也不一样,前者是 80 端口,后者是 443 端口。
  • HTTPS 协议需要到数字认证机构(CA)申请证书,一般需要一定的费用。
  • HTTP 页面响应比 HTTPS 快,主要因为 HTTP 使用 3 次握手建立连接,而 HTTPS 除了 TCP 的 3 次握手,还需要经历一个 SSL 协商过程。

HTTP/1.1 和 HTTP/1.0 的区别

  • 长连接:HTTP/1.0 默认浏览器和服务器之间保持短暂连接,HTTP/1.1 默认使用的是持久连接。
  • 节约带宽:当客户端请求某个资源时,HTTP/1.0 默认将该资源相关的整个对象传送给请求方,但很多时候可能客户端并不需要对象的所有信息。而 HTTP/1.1 允许只请求部分资源,节约带宽。
  • 错误通知的管理:HTTP/1.1 在 1.0 的基础上新增了 24 个错误状态响应码。例如 414 表示客户端请求中所包含的 URL 地址太长,以至于服务器无法处理。
  • 缓存处理:HTTP/1.1 请求头中添加了更多与缓存相关的字段,从而支持更为灵活的缓存策略。

HTTP/1.X 和 HTTP/2.0 的区别

  • 相比于 HTTP/1.X 的文本(字符串)传送, HTTP/2.0 采用二进制传送。
  • HTTP/2.0 头部压缩,同时通信双方会维护一张头信息表,大大减小了重传次数和数据量。
  • HTTP/2.0 支持服务器推送。 服务器在客户端未经请求许可的情况下,可预先向客户端推送需要的内容。
  • HTTP/2.0 支持多路复用。

HTTPS的加密方式

HTTPS 采用对称加密和非对称加密相结合的方式,首先使用 SSL/TLS 协议进行加密传输,为了弥补非对称加密的缺点,HTTPS 采用证书来进一步加强非对称加密的安全性,通过非对称加密,客户端和服务端协商好之后进行通信传输的对称密钥,后续的所有信息都通过该对称秘钥进行加密解密,完成整个 HTTPS 的流程。

CA( Certification Authority),证书颁发机构,防止服务器伪造,内含公钥和私钥,使用 CA 公钥进行验证真伪。

对称加密、非对称加密优缺点?

  • 对称加密:对称加密算法又称传统加密算法。 加密和解密使用同一个密钥。

    • 优点:计算量小,加密速度快,加密效率高
    • 缺点:安全性得不到保证
  • 非对称加密: 非对称加密算法需要两个密钥:公开密钥(publickey) 和私有密钥(privatekey),公开密钥和私有密钥是一对。如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密,反之也是这样。

    • 优点:算法强度复杂,安全性高
    • 缺点:加密解密速度慢,只适合对少量数据进行加密

DNS域名解析的流程?

通过UDP或者TCP传输,一般采用UDP

  • 先浏览器缓存,再到host
  • 本地域名服务
  • 根域名服务器“.”
  • 顶级域名服务器“edu, gov, com, net”
  • 二级域名服务器“baidu, google”

点对点和端对端的区别?

  • 点到点是主机到主机之间的通信。端到端是进程到进程之间的通信。
  • 一台计算机可以与很多台计算机进行通信,使用IP对不同的计算机进行区分(点到点)。
  • 一台计算机上的一个程序(例如QQ)和很多计算机上的程序通信,需要使用IP+端口才能唯一的表示一个会话。

Cookie和Session的区别?

  1. 主要区别是,cookie数据保存在客户端,session数据保存在服务器端
  2. cookie放在别人那不是很安全。
  3. 当访问量增多时,session会占用服务器的性能。如果要减轻服务器压力,应用cookie
  4. 单个cookie在客户端的限制是3k
  5. 所以,登陆信息等重要信息存放为session;其他信息要保留存放为cookie。

什么是负载均衡?

含义是将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,从而协同完成工作任务。

例如京东等大型用户网站为了处理海量用户发起的请求,其往往采用分布式服务器,并通过引入 反向代理 等方式将用户请求均匀分发到每个服务器上,而这一过程实现的就是负载均衡。

反向代理:反向代理隐藏了真实的服务端,当我们请求百度的时候,就像拨打10086一样,背后可能有成千上万台服务器为我们服务,但具体是哪一台,你不知道,也不需要知道,你只需要知道反向代理服务器是谁就好了,www.baidu.com 就是我们的反向代理服务器,反向代理服务器会帮我们把请求转发到真实的服务器那里去。Nginx 就是性能非常好的反向代理服务器,用来做负载均衡。

从浏览器输入url后都经历了什么

① DNS解析:当用户输入一个网址并按下回车键的时候,浏览器获得一个域名,而在实际通信过程中,我们需要的是一个 IP 地址,因此我们需要先把域名转换成相应 IP 地址。

② TCP连接:浏览器通过 DNS 获取到 Web 服务器真正的地址后,便向 Web 服务器发起 TCP 连接请求,通过三次握手建立好连接后,浏览器便可以将 HTTP 请求数据发送给服务器了。

③ 发送HTTP请求:浏览器向 Web 服务器发起一个 HTTP 请求,HTTP 协议是建立在 TCP 协议之上的应用层协议,其本质是在建立好的 TCP 连接中,按照 HTTP 协议标准发送一个索要网页的请求。这一过程中,会涉及到负载均衡等操作。

④ 处理请求并返回:服务器获取到客户端的 HTTP 请求后,会根据 HTTP 请求中的内容来决定如何获取相应的文件,并将文件发送给服务器。

⑤ 浏览器渲染:浏览器根据响应开始显示页面,首先解析 HTML 文件构建 DOM 树,然后解析 CSS 文件渲染树,等到渲染树构建完成后,浏览器开始布局渲染树并将它绘制到屏幕上。

⑥ 断开连接:客户端和服务器通过四次挥手终止 TCP 连接。

传输层

TCP 和 UDP 的区别?

类型是否面向连接传输可靠性传输形式传输效率所需资源首部字节
TCP面向连接可靠字节流20~60
UDP无连接不可靠数据报文段8 个字节

为什么有了TCP还需要UDP?各自适用场景?

因为UDP有简单、传输快的优势,在越来越多场景下取代了TCP,如实时游戏。现代网速的提升使得UDP的丢包率降低,如果使用应用层重传,还能够确保传输的可靠性。

如果采用TCP,一旦发生丢包,TCP会将后续的包缓存起来,接收重传的包后再继续发送,延时会越来越大。

  • TCP适用场景:适用于要求可靠运输的应用,例如:文件传输、邮件传输。
  • UPD适用场景:适用于实时应用,例如:直播、即时通信、域名转换。

UDP实现可靠传输的设计思路?

在应用层模仿传输层TCP的可靠性传输。

  1. 添加seq/ack机制,确保数据发送到对端
  2. 添加发送和接收缓冲区。
  3. 添加超时重传机制。

UPD首部字段和长度?

16位源端口、16位目标端口、16位UDP长度、16位UDP校验和(一共 8 个字节)。

深入理解 TCP 协议:从原理到实战

TCP概述

一句话描述TCP协议:TCP是一个可靠的、面向连接的、基于字节流的、全双工的协议。

  • 面向连接

    面向连接的协议要求正式发送数据之前需要通过握手建立一个逻辑连接,结束通信时也是通过有序的四次挥手来断开连接

  • 可靠的

    IP是一种无连接、不可靠的协议,TCP想要在IP基础上构建可靠的传输层协议,必须有一个复杂的机制来保障。主要有:

    • 数据分块:应用数据被分割成 TCP 认为最适合发送的数据块。
    • 校验和:每个TCP包的首部中都有两字节用来表示校验和,防止在传输过程中有损坏。如果收到一个校验和有差错的报文,TCP不会发送任何确定直接丢弃它,等待发送端重传。
    • 包的序列号:解决了接收数据的乱序、重复问题。
    • 超时重传:当 TCP 发出一个报文段后,它启动一个定时器;如果超过某个时间还没有收到确认,将重发这个报文段。
    • ARQ协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
    • 流量控制:TCP 连接的双方都有一个固定大小的缓冲空间,发送方发送的数据量不能超过接收端缓冲区的大小。当接收方来不及处理发送方的数据,会提示发送方降低发送的速率,防止产生丢包。
    • 拥塞控制:当网络某个节点发生拥塞时,减少数据的发送。
  • 是面向字节流的

TCP是一种字节流(byte-stream)协议,流的含义是没有固定的报文边界

假设你调用2次write函数往socket里一次写500字节、800字节。write函数只是把字节拷贝到内核缓冲区,最终会以多少条报文发送出去是不确定的。

  • 是全双工的

在TCP中发送端和接收端可以是客户端/服务端,也可以是服务端/客户端,通信的双方在任意时刻既可接收数据也可以是发送数据。

剖析TCP首部字段

TCP头部是支撑 TCP 复杂功能的基石。完整的TCP头部如下图所示:

  • 源端口号、目标端口号

TCP报文头部里没有源 ip 和目标 ip 地址,只有源端口号和目标端口号。因为那是 IP 层协议的事,TCP 层只有源端口和目标端口。

源IP、源端口、目标IP、目标端口构成了 TCP 连接的四元组。一个四元组可以唯一标识一个连接。

  • 序列号(Sequence number)

TCP 是面向字节流的协议,通过 TCP 传输的每个字节都分配了序列号,序列号指的是本报文段 第一个字节的序列号。

序列号加上报文的长度,就可以确定传输的是哪一段数据。

因为网络层(IP层)不保证包的顺序,TCP 协议利用序列号来解决网络包乱序、重复的问题,以保证数据表以正确的顺序组装传递给上层应用。

初始序列号(Initial Sequence Number, ISN):在建立连接之初,通信双方都会各自选择一个序列号,称之为初始序列号。在建立连接时,通信双方通过SYN报文交换彼此的ISN。

  • 确认号(Acknowledgment number)

TCP使用确认号ACK 来告知对方下一个期望接收的序列号,小于此确认号的所有字节都已经收到。

关于ACK的几个注意点:

  1. 不是所有的包都需要确认
  2. 不是收到了数据包就要立马确认,可以延迟一会再确认
  3. ACK包本身不需要被确认,否则就会无限循环了
  4. 确认号永远是表示小于此确认号的字节都已经收到
  • TCP Flags

TCP有很多种标记,有些用来发起连接同步初始序列号,有些用来确认数据包,还有些用来结束连接。

TCP定义了一个8位的字段用来表示Flags,大部分只用到了后6个,如下图所示

我们通常所说的 SYN、ACK、FIN、RST 其实只是把 flags 对应的 bit 位置为 1 而已,这些标记可以组合使用,比如 SYN+ACK,FIN+ACK 等。

  • 最常见的有下面几个:

    • SYN(synchronized):用于发起连接数据表同步双方的初始序列号
    • ACK(Acknowledge):确认数据包
    • RST(Reset):这个标记用来强制断开连接
    • FIN(Finish):通知对方我发完了所有数据,准备断开连接,后面就不会发数据包给你了。
    • PSH(Push):告知对方这些数据包收到以后应该马上交给上层应用,不能缓存下来。
  • 窗口大小

用于表示窗口大小的“Window Size” 只有16位,也就是最大窗口是2^16^=65535字节(64KB)。

这也太小了,因此TCP协议引入了【TCP窗口缩放】选项作为窗口缩放的比例因子,比例因子的范围是0~14,其中最小值0表示不缩放。比例因子可以将窗口扩大到原来的2的n次方。

例如:窗口大小缩放前为1050,缩放因子为7,则真正的窗口大小为1050*2^7^=134400。

  • 可选项

可选项的格式入下所示

例如MSS,kind=2,length=4,value=1460

常用的选项有以下几个:

  1. MSS:TCP允许的从对方接收的最大报文段
  2. SACK:选择确定选项
  3. Window Scale:窗口缩放选项

MTU与MSS

  • MSS(Maximum Segment Size)最大报文段长度,工作在网络层。

    MTU(Maximum Transmission Unit)最大传输单元,工作在链路层。

  • IP数据包长度在超过链路的MTU时,发送之前需要分片。而TCP层为了IP层不用分片主动将包分割为MSS大小。

三次握手

三次握手的最重要的是交换彼此的 ISN(初始序列号)。

SYN 报文不携带数据,但是却占用一个序号,下一次发送时数据序列号要加一。

除了交换彼此的 ISN,三次握手的另一个作用是交换一些辅助信息,比如 MSS、窗口大小、窗口缩放因子、是否支持选择确认等。

image.png

在握手之前,主动打开连接的客户端结束 CLOSE 阶段,被动打开的服务器也结束 CLOSE 阶段,并进入 LISTEN 阶段。随后进入三次握手阶段:

① 首先客户端向服务器发送一个 SYN 包,并等待服务器确认。随后客户端进入 SYN-SENT 阶段。

  • 标识位为 SYN,表示请求建立连接;
  • 序号为 Seq = x(x一般为1);

② 服务器接收到客户端发来的 SYN 包后,并返回一段 TCP 报文,结束 Listen 状态,进入 SYN-RECV 阶段。

  • 标识位为 SYNAck,表示确认客户端的报文 Seq 序号有效,并同意创建新连接;
  • 序号为 Seq = y
  • 确认号为 Ack = x + 1,表示收到客户端的序号 Seq,并将其加 1 作为自己确认号 Ack 的值;

③ 客户端收到 SYN+ACK 包后,确认了自己能正常发送数据,从而进入到 ESTABLISHED 阶段,并返回最后一段报文。

  • 标识位为 ACK,表示确认收到服务端同意连接的信号;
  • 序号为 Seq = x + 1,表示收到服务端的确认号 Ack,并将其值作为自己的序号值;
  • 确认号为 Ack = y + 1,表示收到服务端的序号 Seq,并将其加 1 作为自己的确认号 Ack 的值。

当服务器收到客户端的最后一段报文后,确认自己能正常发送信息到客户端,从而进入到 ESTABLISHED 阶段,自此完成三次握手。

为什么第 2 次握手传回 ACK,还要传回 SYN?

ACK 是为了告诉客户端发来的数据已经接收到了。

而传回 SYN 是为了告诉客户端,服务端收到的消息确实是客户端发送的消息。

为什么需要三次握手,两次不行吗?那能不能四次握手?

三次握手的主要目的是确认自己和对方的发送和接收都是正常的,从而保证了双方能够进行可靠通信。若采用两次握手,当第二次握手后就建立连接的话,此时客户端知道服务器能够正常接收到自己发送的数据,而服务器并不知道客户端是否能够收到自己发送的数据。

可以四次握手。但是可以合并,这样可以提高连接的速度与效率。

四次挥手

① 客户端调用 close 方法,主动关闭,发送一个 FIN 报文给服务端。随后客户端进入 FIN-WAIT-1 状态,即【半关闭】阶段,并且停止向服务端发送通信数据。

  • 标记位为 FIN,表示请求释放连接;
  • 序号为 Seq = u

② 服务端收到请求断开连接的 FIN 报文后,服务端进入 CLOSE_WAIT 状态,并返回一段 TCP 报文。

  • 标记位为 ACK,表示接收到客户端释放连接的请求;
  • 序号为 Seq = v
  • 确认号为 Ack = u + 1,表示是在收到客户端报文的基础上,将其序号值加 1 作为报文确认号 Ack 的值。

客户端收到服务器发送的 TCP 报文后,确认服务器已经收到了释放连接的请求了,随后客户端进入 FIN-WAIT-2 状态。

③ 服务端在发出 Ack 确认报文后,服务器端会将遗留的待传数据发给客户端,待传输完成后便也做好了关闭连接的准备了,随后进入 LAST-ACK 阶段,停止发送数据。并再次向客户端发送一段 TCP 报文。

  • 标记位为 FINACK,表示服务器已经准备好释放连接;
  • 序号为 Seq = w;
  • 确认号仍然为 Ack = u + 1,表示是在收到客户端报文的基础上,将其序号值加 1 作为报文确认号 Ack 的值。

④ 客户端收到从服务器发来的 TCP 报文,确认了服务器已经做好了释放连接的准备,于是进入 TIME-WAIT 阶段,并向服务器发送一段报文。

  • 标记位为 ACK,表示接收到服务器释放连接的信号;
  • 序号为 Seq = u + 1,将其确认号 Ack 值作为本段序号的值。
  • 确认号为 Ack = w + 1,表示是在收到服务器报文的基础上,将其序号 Seq 的值作为本段报文确认号的值。

发送后客户端在 TIME-WAIT 状态等待 2MSL之后,进入 CLOSED 阶段。服务端收到客户端发出的 TCP 报文后,也进入 CLOSED 阶段。由此完成四次挥手。

为什么FIN和SYN要消耗一个序列号呢?

因为 FIN 和 SYN 信号都是需要 ACK 的,也就是必须回复这个信号,如果它不占用一个字节的话,是判断不出这个 ACK 是回复这个信号 还是回复这个信号之前的数据包的。

例如:如果 FIN 信号不占用一个字节,回复 FIN 的 ACK 包可能被认为是 之前发送的数据包被重新发了一次,第二次挥手无法完成,连接也就无法正常关闭了。

为什么挥手要四次,三次可以吗?

释放 TCP 连接时之所以需要四次挥手,是因为 FIN 释放连接报文ACK 确认接收报文是分别在两次挥手中传输的。 当主动方在数据传送结束后发出连接释放的通知,由于 被动方可能还有必要的数据要处理,所以会先返回 ACK 确认收到报文。当被动方也没有数据再发送的时候,才发出连接释放通知。

例如打电话,我说 “我没东西说了”,对方回答 “知道了”,但是对方可能还有没说完的话,我不能要求对方跟着自己的节奏结束电话,于是对方又说了一通,最后对方说 “我说完了”,我回答 “知道了”,这样通话才算结束。

CLOSE-WAIT 状态是服务端第三次挥手,把剩余的待发送的数据发送给客户端后进入的状态。因此,CLOSE-WAIT 状态的意义就是为了 保证服务器在关闭连接之前将待发送的数据发送完成。

有很多 CLOSE-WAIT 怎么解决

  • 首先检查是不是代码的问题,看是否服务端程序忘记关闭连接。如果是,则修改代码。
  • 调整系统参数,一般一个 CLOSE_WAIT 会维持至少 2 个小时的时间,我们可以通过调整参数来缩短这个时间。

TIME-WAIT 状态的意义

TIME-WAIT 发生在第四次挥手,只有 主动断开的那一方才会进入 TIME_WAIT 状态,且会在那个状态持续 2 个 MSL。原因:

  • 若没有该状态,即客户端在收到服务端的 FIN 报文后立即关闭连接,此时服务端的端口并没有关闭,若客户端在相同的端口立即建立新的连接,则有可能收到上一次连接中残留的数据包,从而导致不可预料的异常出现。
  • 除此之外,假设客户端最后发送的 Ack 包传输时丢失了,服务端没有收到确认。由于 TCP 协议的超时重传机制,服务端将重发 FIN 报文,若客户端直接关闭了。收到服务端重新发送的 FIN 包时,客户端就会用 RST 包来响应服务端,这将会使对方认为是有错误发生,然而这只是正常的关闭过程,并没有出现异常情况。

TIME-WAIT 为什么是 2MSL

MSL(Maximum Segment Lifetime),指一段 TCP 报文在传输过程中的最大生命周期。

  • 如果服务器在 1MSL 后仍然没有收到客户端的 Ack 确认报文,那么它会向客户端重传 FIN 报文,对客户端而言,从客户端发出 ACK 报文起,重传的 FIN 报文的最晚到达时间是 2MSL。
  • 因此 2MSL 为的是确认服务器能否接收到客户端发出的 ACK 确认报文。

大量TIME_WAIT造成的影响,怎么优化?

导致的问题:高并发短连接 的 TCP 服务器上,例如京东、淘宝等,当服务器处理完请求后主动请求关闭连接,这样服务器上会有大量的连接处于 TIME_WAIT 状态,服务器维护每一个连接需要一个 socket,而 socket 的使用是有上限的,如果持续高并发,会导致一些正常的 连接失败。

解决方案:修改配置使 处于 TIME_WAIT 状态下的 socket ,可以能够快速回收重用。 也可以采用长连接的方式,但是长连接的业务中并发量一般不会太高。

TCP 最大连接数限制

  • Client 最大 TCP 连接数

client 在每次发起 TCP 连接请求时,如果自己并不指定端口的话,系统会随机选择一个本地端口,该端口是独占的,不能和其他 TCP 连接共享。本地端口个数最大只有 65536,除了端口 0 不能使用外,其他端口在空闲时都可以正常使用,这样可用端口最多有 65535 个。

  • Server最大 TCP 连接数

理论上最大 TCP 连接数约为 2^32^(IP 数)× 2^16^(port 数) server 端单机最大 TCP 连接数约为 2^48^ 次方。

在实际环境中,一些 IP 地址和端口具有特殊含义,没有对外开放,还有机器资源等限制,一般通过增加内存、配置参数等方式,单机最大并发 TCP 能超过 10 万

SYN Flood 攻击

SYN泛洪攻击是一种 DoS(拒绝服务攻击)。

想象一个场景:客户端大量伪造 IP 发送 SYN 包,服务端回复的 ACK+SYN 去到了一个未知的 IP 地址。会造成服务端大量的连接处于 SYN_RCVD 状态,而服务器的半连接队列大小也是有限制的,如果半连接队列满,也会出现无法处理正常请求的情况。

如何应对 SYN Flood 攻击?
  • 增加SYN连接数
  • 减少发送 SYN+ACK 的重试次数
  • SYN Cookie机制

    • 现在服务器上的tcp_syncookies默认等于1,表示连接队列满时启用。0表示禁用、2表示始终启用。
    • 原理就是:在三次握手的最后阶段才分配连接资源。

重传机制

  • 永远记住 ACK 是表示这之前的包都已经全部收到

如果发送5000个字节的数据包,因为MSS的限制每次传输1000个字节,分5段传输。

数据包 1 发送的数据正常到达接收端,接收端回复 ACK 1001。如果数据包 2 因为某些原因未能到达服务器,其他包正常到达,这时接收端也不能ack 3 4 5数据包,因为数据包 2 还没收到,接收端只能回复 ACK1001。

快速重传机制与 SACK

快速重传的含义是:当接收端收到一个不按序到达的数据段时,TCP 立刻发送 1 个重复 ACK,当发送端收到 3 个或以上重复 ACK,就意识到之前发的包可能丢了,于是马上进行重传,不用等到重传定时器超时再重传。

这里有一个问题,发送 3、4、5 包收到的全部是 ACK=1001,快速重传解决了一个问题: 需要重传。因为除了 2 号包,3、4、5包也可能丢失,那到底是只重传 2 号包还是重传 2,3,4,5 所有包呢?

聪明的网络协议设计者,想到了一个好办法:

  • 收到 3 号包的时候在 ACK 包中告诉发送端。我目前收到的最大连续的包序号是1000(ACK=1001),[1:1001]、[2001:3001]区间的包我也收到了
  • 收到 4 号包的时候在 ACK 包中告诉发送端。我目前收到的最大连续的包序号是1000(ACK=1001),[1:1001]、[2001:4001]区间的包我也收到了
  • 收到 5 号包的时候在 ACK 包中告诉发送端。我目前收到的最大连续的包序号是1000(ACK=1001),[1:1001]、[2001:5001]区间的包我也收到了

这样发送端就清楚知道只用重传 2 号数据包就可以了,数据包3、4、5已经确认无误的被对端收到了。这种方式被称为 SACK(Selective Acknowledgment)

TCP流量控制(滑动窗口)

TCP 会把要发送的数据放入发送缓冲区(Send Buffer),接收到的数据放入接收缓冲区(Receive Buffer),应用程序会不停的读取接收缓冲区的内容进行处理。

流量控制做的事情就是,如果接受缓冲区已满,发送端应该停止发送数据。

为了控制发送端的速率,接收端会告知客户端自己的接收窗口(rwnd),也就是接受缓冲区中空闲的部分。

TCP在收到数据包回复的 ACK 包里会带上自己接收窗口的大小,发送端会根据这个值调整发送策略。

发送窗口和接收窗口

当对方的 ACK 包中表明自己的接收窗口大小后,发送端会把自己的 [发送窗口] 限制在这个大小以内。

如果处理能力有限,导致接收缓冲区满,接收窗口大小为 0,发送端应该停止发送数据。

TCP包状态分类

从 TCP 角度而言,数据包的状态可以分为四种:

  • 粉色部分#1:表示已发送并且已经收到 确认ACK 的数据包
  • 蓝色部分#2:表示已发送但是还没收到 确认ACK 的数据包。如果在一段时间内没有收到 ACK,发送端需要重传这部分数据包。
  • 绿色部分#3:表示未发送,但接收端有空间可以接收的数据包
  • 黄色部分#4:表示未发送,而且这部分接收端没有空间接收的数据包

发送窗口(send window)和可用窗口(usable window)

发送窗口表示在某个时刻,发送端被允许发送的最大数据包大小,包括还没收到确认ACK的数据包(#2、#3区域)

可用窗口是发送端还能发送的最大数据包大小(#3区域)

如果上图中的可用窗口的46~51发送出去,可用窗口区间减小到 0,这个时候只有收到接收端的 ACK 数据,否则发送端将不能发送数据。

因此,流量控制实际上是对【发送方数据流量】的控制。

拥塞控制

流量控制这种机制确实可以防止发送端向接收端过多的发送数据,但是它只关注了发送端和接收端自身的状况,而没有考虑整个网络的通信状况。于是出现了我们今天要讲的拥塞处理。

拥塞处理涉及下面这几个算法:

  1. 慢启动(Slow Start)
  2. 拥塞避免(Congestion Avoidance)
  3. 快速重传(Fast Retransmit)和 快速恢复(Fast Recovery)

为了实现上面算法,TCP的每条连接都有两个核心值:

  1. 拥塞窗口(Congestion Window,cwnd)
  2. 慢启动阙值(Slow Start Threshold,ssthresh)

拥塞窗口

拥塞窗口(cwnd)和接收窗口(rwnd)有什么区别呢?

  • 接收窗口是接收端的限制,是接收端还能接收的数据量大小
  • 拥塞窗口是发送端的限制,是发送端在还未收到对端 ACK 之前还能发送的数据量大小

我们在TCP头部的windows字段讲的是 接收窗口大小。

拥塞窗口初始值等于操作系统的一个变量 initcwnd,最新的 linux 系统 initcwnd 默认值等于 10。

  • 真正的发送窗口大小 = 【接收端窗口大小】 与 【发送端自己的拥塞窗口大小】两者的最小值

如果接收窗口比拥塞窗口小,表示接收端处理能力不足。如果拥塞窗口小于接收窗口,表示接收端有处理能力,但网络拥塞。

因为发送端能发送多少数据,取决于两个因素:

  1. 对方能接收多少(接收窗口)
  2. 自己为了避免网络拥塞主动减少数据量(拥塞窗口)

发送端和接收端不会交换 拥塞窗口cwnd 这个值,这个值是维护在发送端本地内存中的一个值

拥塞控制的算法本质是控制拥塞窗口(cwnd)的变化。

拥塞处理算法之:慢启动

拥塞控制是从整个网络的大局观来控制的,如果有足够的带宽,你可以选择用最快的速度传输数据。但是如果是一个缓慢的移动网络,发送数据过多,只是造成更大的网络延迟。

每个 TCP 连接都有一个拥塞窗口的限制,最初这个值很小,随着时间的推移,每次发送的数据量如果在不丢包的情况下,“慢慢”的递增,这种机制被称为【慢启动】

  • 算法过程:

    • 第一步,三次握手以后,双方通过 ACK 告诉对方自己接收窗口(rwnd)大小,准备就绪。
    • 第二步,通信双方各自初始化自己的 [拥塞窗口](cwnd)大小
    • 第三步,cwnd初始值较小时,每收到一个ACK,cwnd+1;每经过一个 RTT(往返时延),cwnd变为之前的两倍。

慢启动阙值(Slow Start Threshold,ssthresh)

慢启动算法的拥塞窗口(cwnd)肯定不能永无止境的指数级增长下去,它的阙值称为【慢启动阙值】。

  • 当 cwnd < ssthresh 时,拥塞窗口按指数级增长(慢启动)
  • 当 cwnd > ssthresh 时,拥塞窗口按线性增长(拥塞避免)

拥塞处理算法之:拥塞避免(Congestion Avoidance)

当 cwnd > ssthresh 时,拥塞窗口进入「拥塞避免」阶段。

与慢启动的区别在于:每经过一个 RTT 才将拥塞窗口加 1,不管期间收到多少个 ACK。

拥塞处理算法之:快速重传 和 快速恢复

快恢复算法是和快重传算法配合使用的,该算法主要有以下两个要点:

① 当发送方连续收到三个重复确认,拥塞阙值 ssthresh 值减半

② 由于发送方可能认为网络现在没有拥塞,因此与慢开始不同,把 cwnd 值设置为 ssthresh 减半之后的值,然后执行拥塞避免算法,线性增大 cwnd。

TCP 粘包问题

待补充~


为什么算法这么难
16 声望3 粉丝

我想要清净一下~


下一篇 »
JVM调优