TCP、HTTP、HTTPS、UDP

整理一下,以后也许用得着。

只记录了八股常见的,真正详细的得看MDN Web Docs (mozilla.org)

不过MDN能看多少是多少吧。

输入URL到显示页面的全过程

和这篇有关系但不大,但感觉这个有点好玩,所以记下来,反正以后也要会。

基础版本

  • 浏览器根据请求的 URL 交给 DNS 域名解析,找到真实 IP ,向服务器发起请求
  • 服务器交给后台处理完成后返回数据,浏览器接收⽂件HTMLJSCSS 、图象等);
  • 浏览器对加载到的资源( HTMLJSCSS 等)进⾏语法解析,建立相应的内部数据结构 (如 HTMLDOM);
  • 载⼊解析到的资源⽂件,渲染页面,完成。

略微详细的

  • 在浏览器地址栏输⼊URL

  • 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤

    • 如果资源未缓存,发起新请求
    • 如果已缓存,检验是否⾜够新鲜,⾜够新鲜直接提供给客户端,否则与服务器进⾏验证。
    • 检验新鲜通常有两个HTTP头进⾏控制 ExpiresCache-Control
      • HTTP1.0提供 Expires,值为⼀个绝对时间表示缓存新鲜⽇期
      • HTTP1.1增加了Cache-Control: max-age=time,值为以秒为单位的最⼤新鲜时间
  • 浏览器解析URL获取协议,主机,端⼝,path

  • 浏览器组装⼀个HTTP(GET)请求报⽂

  • 浏览器获取主机 ip 地址,过程如下:

    • 浏览器缓存
    • 本机缓存
    • hosts文件(操作系统缓存)
    • 路由器缓存
    • ISP DNS缓存
    • 根服务器DNS递归查询(可能因为负载均衡而导致每次的IP都不一样)
  • 打开⼀个socket与⽬标IP地址,端⼝建⽴TCP链接,三次握⼿如下:

    • 客户端发送⼀个TCPSYN=1Seq=X的包到服务器端口
    • 服务器发回SYN=1ACK=X+1Seq=Y的响应包
    • 客户端发送ACK=Y+1Seq=Z
  • TCP链接建⽴后发送HTTP请求

  • 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使⽤HTTP Host头部判断请求的服务程序

  • 服务器检查**HTTP请求头是否包含缓存验证信息**,如果验证缓存新鲜,返回304等对应状态码。

    HTTP 304 Not Modified说明无需再次传输请求的内容,也就是说可以使用缓存的内容。

  • 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作

  • 服务器将响应报⽂通过TCP连接发送回浏览器

  • 浏览器接收HTTP响应,然后根据情况选择关闭TCP连接或者保留重⽤,关闭TCP连接的四次握⼿如下:

    • 主动⽅发送Fin=1Ack=ZSeq= X报⽂
    • 被动⽅发送ACK=X+1Seq=Z报⽂
    • 被动⽅发送Fin=1ACK=XSeq=Y报⽂
    • 主动⽅发送ACK=YSeq=X报⽂
  • 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同

  • 如果资源可缓存,进行缓存

  • 对响应进行解码(例如gzip压缩)

  • 根据资源类型决定如何处理(假设资源为HTML⽂档)

  • 解析HTML⽂档构件DOM树下载资源构造CSSOM树执⾏js脚本,这些操作没有严 格的先后顺序,以下分别解释:

    • 构建DOM树
      • Tokenizing:根据HTML规范将字符流解析为标记
      • Lexing:词法分析将标记转换为对象并定义属性和规则
      • DOM construction:根据HTML标记关系将对象组成DOM
    • 解析过程中遇到图⽚、样式表、js⽂件,启动下载
    • 构建CSSOM树
      • Tokenizing:字符流转换为标记流
      • Node:根据标记创建节点
      • CSSOM:节点创建CSSOM
    • 根据DOM树和CSSOM树构建渲染树 :
      • DOM树的根节点遍历所有可⻅节点,不可⻅节点包括:
        • script , meta 这样本身 不可⻅的标签。
        • css隐藏的节点,如 display: none
      • 对每⼀个可⻅节点,找到恰当的CSSOM规则并应⽤
      • 发布可视节点的内容和计算样式
    • js解析如下:
      • 浏览器创建Document对象并解析HTML,将解析到的元素和⽂本节点添加到⽂档中,此时**document.readystateloading**
      • HTML解析器遇到没有async和defer的script时,将他们添加到⽂档中,然后执⾏⾏内 或外部脚本。这些脚本会同步执⾏,并且在脚本下载和执⾏时解析器会暂停。这样就可以⽤**document.write()**把⽂本插⼊到输⼊流中。同步脚本经常简单定义函数和注册事件处理程序,他们可以遍历和操作script和他们之前的⽂档内容
      • 当解析器遇到设置了async属性的script,开始下载脚本并继续解析⽂档。脚本会在它 下载完成后尽快执⾏,但是解析器不会停下来等它下载。异步脚本禁止使⽤ **document.write()**,它们可以访问⾃⼰script和之前的⽂档元素
      • 当⽂档完成解析,document.readState变成interactive
      • 所有defer脚本会按照在⽂档出现的顺序执⾏,延迟脚本能访问完整⽂档树,禁止使⽤ document.write()
      • 浏览器在Document对象上触发DOMContentLoaded事件
      • 此时⽂档完全解析完成,浏览器可能还在等待如图⽚等内容加载,等这些内容完成载⼊ 并且所有异步脚本完成载⼊和执⾏,document.readState变为completewindow触发 load事件
  • 显示⻚⾯(HTML解析过程中会逐步显示⻚⾯)

详细简略版本

  • 从浏览器接收 url 到开启⽹络请求线程(这⼀部分可以展开浏览器的机制以及进程与线程 之间的关系)
  • 开启⽹络线程到发出⼀个完整的 HTTP 请求(这⼀部分涉及到dns查询, TCP/IP 请求,五层因特⽹协议栈等知识)
  • 从服务器接收到请求到对应后台接收到请求(这⼀部分可能涉及到负载均衡,安全拦截以及后台内部的处理等等)
  • 后台和前台的 HTTP 交互(这⼀部分包括 HTTP 头部、响应码、报⽂结构、 cookie 等知 识,可以提下静态资源的 cookie 优化,以及编码解码,如 gzip 压缩等)
  • 单独拎出来的缓存问题, HTTP 的缓存(这部分包括http缓存头部, ETag , catchcontrol 等)
  • 浏览器接收到 HTTP 数据包后的解析流程(解析 html、 词法分析然后解析成 dom 树、解析 css ⽣成 css 规则树、合并成 render 树,然后 layout 、 painting 渲染、复合图层的合成、 GPU 绘制、外链资源的处理、 loaded 和 DOMContentLoaded 等)
  • CSS 的可视化格式模型(元素的渲染规则,如包含块,控制框, BFCIFC 等概念)
  • JS 引擎解析过程( JS 的解释阶段,预处理阶段,执⾏阶段⽣成执⾏上下⽂, VO ,作 ⽤域链、回收机制等等)
  • 其它(可以拓展不同的知识模块,如跨域,web安全, hybrid 模式等等内容)

HTTP

HTTP协议(超文本传输协议HyperText Transfer Protocol),它是基于TCP协议的应用层传输协议,简单来说就是客户端和服务端进行数据传输的一种规则。

HTTP 是一种无状态 (stateless) 协议, HTTP协议本身不会对发送过的请求和相应的通信状态进行持久化处理。这样做的目的是为了保持HTTP协议的简单性,从而能够快速处理大量的事务, 提高效率。

然而,在许多应用场景中,我们需要保持用户登录的状态或记录用户购物车中的商品。由于HTTP是无状态协议,所以必须引入一些技术来记录管理状态,例如Cookie

URL格式

img

HTTP常用的请求方式

方法 作用
GET 获取资源
POST 传输实体主体
PUT 上传文件
DELETE 删除文件
HEAD 和GET方法类似,但只返回报文首部,不返回报文实体主体部分
PATCH 对资源进行部分修改
OPTIONS 查询指定的URL支持的方法
CONNECT 要求用隧道协议连接代理
TRACE 服务器会将通信路径返回给客户端

为了方便记忆,可以将PUT、DELETE、POST、GET理解为客户端对服务端的增删改查。

  • PUT:上传文件,向服务器添加数据,可以看作增
  • DELETE:删除文件
  • POST:传输数据,向服务器提交数据,对服务器数据进行更新。
  • GET:获取资源,查询服务器资源

GET与POST请求的区别

Post 和 Get 是 HTTP 请求的两种方法,其区别如下:

  • 应用场景: GET 请求是一个幂等的请求,一般 Get 请求用于对服务器资源不会产生影响的场景,比如说请求一个网页的资源。而 Post 不是一个幂等的请求,一般用于对服务器资源会产生影响的情景,比如注册用户这一类的操作。
  • 是否缓存: 因为两者应用场景不同,浏览器一般会对 Get 请求缓存,但很少对 Post 请求缓存。
  • 发送的报文格式: Get 请求的报文中实体部分为空,Post 请求的报文中实体部分一般为向服务器发送的数据。
  • 安全性: Get 请求可以将请求的参数放入 url 中向服务器发送,这样的做法相对于 Post 请求来说是不太安全的,因为请求的 url 会被保留在历史记录中。
  • 请求长度: 浏览器由于对 url 长度的限制,所以会影响 get 请求发送数据时的长度。这个限制是浏览器规定的,并不是 RFC 规定的。
  • 参数类型: post 的参数传递支持更多的数据类型。

幂等性:
幂等性可以简单的理解为同一操作执行一次,以及后续的多次执行,对系统状态的影响是一致的。而对于上述我们所讲的方法中,GET,PUT,DELETE,HEAD,OPTIOS都是幂等操作,而POST不是。

POST和PUT

PUT是幂等的,POST不是幂等的。

有些里头说PUT也可以用于创建资源,所以是否能用于创建资源不能作为判断依据,还是用幂等区分比较好。

OPTIONS

OPTIONS是除了GET和POST之外的其中一种 HTTP请求方法。

OPTIONS方法是用于请求获得由Request-URI标识的资源在请求/响应的通信过程中可以使用的功能选项。通过这个方法,客户端可以在采取具体资源请求之前,决定对该资源采取何种必要措施,或者了解服务器的性能。该请求方法的响应不能缓存。

OPTIONS请求方法的主要用途有两个:

  • 获取服务器支持的所有HTTP请求方法;
  • 用来检查访问权限。例如:在进行 CORS 跨域资源共享时,对于复杂请求,就是使用 OPTIONS 方法发送嗅探请求,以判断是否有对指定资源的访问权限。

如果不想让每个CORS复杂请求都出两次请求(预检请求和实际请求),可以设置Access-Control-Max-Age这个属性。让浏览器缓存,在缓存的有效期内,所有options请求都不会发送。优化性能。

常见的HTTP请求头和响应头

HTTP Request Header 常见的请求头:

  • Accept:浏览器能够处理的内容类型
  • Accept-Charset:浏览器能够显示的字符集
  • Accept-Encoding:浏览器能够处理的压缩编码
  • Accept-Language:浏览器当前设置的语言
  • Connection:浏览器与服务器之间连接的类型
  • Cookie:当前页面设置的任何Cookie
  • Host:发出请求的页面所在的域
  • Referer:发出请求的页面的URL
  • User-Agent:浏览器的用户代理字符串

HTTP Responses Header 常见的响应头:

  • Date:表示消息发送的时间,时间的描述格式由rfc822定义
  • server:服务器名称
  • Connection:浏览器与服务器之间连接的类型
  • Cache-Control:控制HTTP缓存
  • content-type:表示后面的文档属于什么MIME类型
    • application/x-www-form-urlencoded:浏览器的原生 form 表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。该种方式提交的数据放在 body 里面,数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL转码。
    • multipart/form-data:该种方式也是一个常见的 POST 提交方式,通常表单上传文件时使用该种方式。
    • application/json:服务器消息主体是序列化后的 JSON 字符串。
    • text/xml:该种方式主要用来提交 XML 格式的数据。
    • 具体见关于常用的http请求头以及响应头详解 - 掘金 (juejin.cn)

HTTP常见的状态码

  • 200:服务器已成功处理了请求。 通常,这表示服务器提供了请求的网页。
  • 301 : (永久移动) 请求的网页已永久移动到新位置。 服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。
  • 302:(临时移动) 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来进行以后的请求。
  • 400 :客户端请求有语法错误,不能被服务器所理解。
  • 403 :服务器收到请求,但是拒绝提供服务。
  • 404 :(未找到) 服务器找不到请求的网页。
  • 500: (服务器内部错误) 服务器遇到错误,无法完成请求。

img

状态码301/302

共同点:301和302状态码都表示重定向,就是说浏览器在拿到服务器返回的这个状态码后会自动跳转到一个新的URL地址,这个地址可以从响应的Location首部中获取(用户看到的效果就是他输入的地址A瞬间变成了另一个地址B)。 不同点:301表示旧地址A的资源已经被永久地移除了(这个资源不可访问了),搜索引擎在抓取新内容的同时也将旧的网址交换为重定向之后的网址;302表示旧地址A的资源还在(仍然可以访问),这个重定向只是临时地从旧地址A跳转到地址B,搜索引擎会抓取新的内容而保存旧的网址。 SEO中302好于301。

补充,重定向原因

  1. 网站调整(如改变网页目录结构);
  2. 网页被移到一个新地址;
  3. 网页扩展名改变(如应用需要把.php改成.Html或.shtml)。

状态码304

服务器为了提高网站访问速度,对之前访问的部分页面指定缓存机制,当客户端在此对这些页面进行请求,服务器会根据缓存内容判断页面与之前是否相同,若相同便直接返回304,此时客户端调用缓存内容,不必进行二次下载。

状态码304不应该认为是一种错误,而是对客户端有缓存情况下服务端的一种响应。

搜索引擎蜘蛛会更加青睐内容源更新频繁的网站。通过特定时间内对网站抓取返回的状态码来调节对该网站的抓取频次。若网站在一定时间内一直处于304的状态,那么蜘蛛可能会降低对网站的抓取次数。相反,若网站变化的频率非常之快,每次抓取都能获取新内容,那么日积月累,的回访率也会提高。

产生较多304状态码的原因:

  • 页面更新周期长或不更新
  • 纯静态页面或强制生成静态html

304状态码出现过多会造成以下问题:

  • 网站快照停止;
  • 收录减少;
  • 权重下降。

HTTP报文格式

请求报文

  1. 请求行(请求方法+URI协议+版本)
  2. 请求头部
  3. 空行
  4. 请求主体
1
2
3
4
5
6
7
8
9
GET/sample.jspHTTP/1.1 请求行
Accept:image/gif.image/jpeg, 请求头部
Accept-Language:zh-cn
Connection:Keep-Alive
Host:localhost
User-Agent:Mozila/4.0(compatible;MSIE5.01;Window NT5.0)
Accept-Encoding:gzip,deflate

username=jinqiao&password=1234 请求主体

响应报文

  1. 状态行(版本+状态码+原因短语)
  2. 响应首部
  3. 空行
  4. 响应主体
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Server:Apache Tomcat/5.0.12
Date:Mon,6Oct2003 13:23:42 GMT
Content-Length:112

<html>
<head>
<title>HTTP响应示例<title>
</head>
<body>
Hello HTTP!
</body>
</html>

HTTP版本区别

HTTP 1.0/1.1

HTTP 1.0和 HTTP 1.1 有以下区别

  • 连接方面,http1.0 默认使用非持久连接,而 http1.1 默认使用持久连接。http1.1 通过使用持久连接来使多个 http 请求复用同一个 TCP 连接,以此来避免使用非持久连接时每次需要建立连接的时延。
  • 资源请求方面,在 http1.0 中,存在一些浪费带宽的现象,例如客户端只是需要某个对象的一部分,而服务器却将整个对象送过来了,并且不支持断点续传功能,http1.1 则在请求头引入了 range 头域,它允许只请求资源的某个部分,即返回码是 206(Partial Content),这样就方便了开发者自由的选择以便于充分利用带宽和连接。
  • 缓存方面,在 http1.0 中主要使用 header 里的 If-Modified-Since、Expires 来做为缓存判断的标准,http1.1 则引入了更多的缓存控制策略,例如 Etag、If-Unmodified-Since、If-Match、If-None-Match 等更多可供选择的缓存头来控制缓存策略。
  • http1.1 中新增了 host 字段,用来指定服务器的域名。http1.0 中认为每台服务器都绑定一个唯一的 IP 地址,因此,请求消息中的 URL 并没有传递主机名(hostname)。但随着虚拟主机技术的发展,在一台物理服务器上可以存在多个虚拟主机,并且它们共享一个IP地址。因此有了 host 字段,这样就可以将请求发往到同一台服务器上的不同网站。
  • http1.1 相对于 http1.0 还新增了很多请求方法,如 PUT、HEAD、OPTIONS 等。

HTTP 1.1/2.0

  • 二进制协议:HTTP/2 是一个二进制协议。在 HTTP/1.1 版中,报文的头信息必须是文本(ASCII 编码),数据体可以是文本,也可以是二进制。HTTP/2 则是一个彻底的二进制协议,头信息和数据体都是二进制,并且统称为”帧”,可以分为头信息帧和数据帧。 帧的概念是它实现多路复用的基础。
  • 多路复用: HTTP/2 实现了多路复用,HTTP/2 仍然复用 TCP 连接,但是在一个连接里,客户端和服务器都可以同时发送多个请求或回应,而且不用按照顺序一一发送,这样就避免了”队头堵塞”的问题。
  • 数据流: HTTP/2 使用了数据流的概念,因为 HTTP/2 的数据包是不按顺序发送的,同一个连接里面连续的数据包,可能属于不同的请求。因此,必须要对数据包做标记,指出它属于哪个请求。HTTP/2 将每个请求或回应的所有数据包,称为一个数据流。每个数据流都有一个独一无二的编号。数据包发送时,都必须标记数据流 ID ,用来区分它属于哪个数据流。
  • 头信息压缩: HTTP/2 实现了头信息压缩,由于 HTTP 1.1 协议不带状态,每次请求都必须附上所有信息。所以,请求的很多字段都是重复的,比如 Cookie 和 User Agent ,一模一样的内容,每次请求都必须附带,这会浪费很多带宽,也影响速度。HTTP/2 对这一点做了优化,引入了头信息压缩机制。一方面,头信息使用 gzip 或 compress 压缩后再发送;另一方面,客户端和服务器同时维护一张头信息表字典,所有字段都会存入这个表,生成一个索引号,以后就不发送同样字段了,只发送索引号,这样就能提高速度了。
  • 服务器推送: HTTP/2 允许服务器未经请求,主动向客户端发送资源,这叫做服务器推送。使用服务器推送提前给客户端推送必要的资源,这样就可以相对减少一些延迟时间。这里需要注意的是 http2 下服务器主动推送的是静态资源,和 WebSocket 以及使用 SSE 等方式向客户端发送即时数据的推送是不同的。

队头阻塞是由 HTTP 基本的“请求 - 应答”模型所导致的。HTTP 规定报文必须是“一发一收”,这就形成了一个先进先出的“串行”队列。队列里的请求是没有优先级的,只有入队的先后顺序,排在最前面的请求会被最优先处理。如果队首的请求因为处理的太慢耽误了时间,那么队列里后面的所有请求也不得不跟着一起等待,结果就是其他的请求承担了不应有的时间成本,造成了队头堵塞的现象。

管道化和多路复用的区别:

csdn上的一段解释:

HTTP/1.1 最大的变化就是引入了持久连接(persistent connection),在HTTP/1.1中默认开启 Connection: keep-alive,即TCP连接默认不关闭,可以被多个请求复用。
那么管道机制就是在同一个TCP连接中可以同时发送多个HTTP请求而不用等待上一个请求返回数据后,再发送下一个请求。虽然可以同时发送多个HTTP请求,但是服务器响应是按照请求的顺序进行响应的。
HTTP 2.0的多路复用是在同一个TCP连接中,可以发送多个HTTP请求,而且请求的响应不依赖于前一个请求。每个请求单独处理,不会出现HTTP1.1中上一个请求没有回应便一直等待的情况。
极客时间的一段解释:
在 HTTP/2 中,多个请求是跑在一个 TCP 管道中的,如果其中任意一路数据流中出现了丢包的情况,那么就会阻塞该 TCP 连接中的所有请求。这不同于 HTTP/1.1,使用 HTTP/1.1 时,浏览器为每个域名开启了 6 个 TCP 连接,如果其中的 1 个 TCP 连接发生了队头阻塞,那么其他的 5 个连接依然可以继续传输数据。

http发展史(http0.9、http1.0、http1.1、http2、http3)梳理笔记 - 掘金 (juejin.cn)

HTTP 与 HTTPS 的区别

HTTP HTTPS
端口 80 443
安全性 无加密,安全性较差 有加密机制,安全性较高
资源消耗 较少 由于加密处理,资源消耗更多
是否需要证书 不需要 需要
协议 运行在TCP协议之上 运行在SSL协议之上,SSL运行在TCP协议之上

HTTPS 的优缺点

优点

  • 安全性:
    • 使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;
    • HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。
    • HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。
  • SEO方面:谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。

缺点

  • 在相同网络环境中,HTTPS 相比 HTTP 无论是响应时间还是耗电量都有大幅度上升。
  • HTTPS 的安全是有范围的,在黑客攻击、服务器劫持等情况下几乎起不到作用。
  • 在现有的证书机制下,中间人攻击依然有可能发生。
  • HTTPS 需要更多的服务器资源,也会导致成本的升高。

HTTPS 的原理

img

图片来源:https://segmentfault.com/a/1190000021494676

加密流程按图中的序号分为:

  1. 客户端请求 HTTPS 网址,然后连接到 server 的 443 端口 (HTTPS 默认端口,类似于 HTTP 的80端口)。

  2. 采用 HTTPS 协议的服务器必须要有一套数字 CA (Certification Authority)证书。颁发证书的同时会产生一个私钥和公钥。私钥由服务端自己保存,不可泄漏。公钥则是附带在证书的信息中,可以公开的。证书本身也附带一个证书电子签名,这个签名用来验证证书的完整性和真实性,可以防止证书被篡改。

  3. 服务器响应客户端请求,将证书传递给客户端,证书包含公钥和大量其他信息,比如证书颁发机构信息,公司信息和证书有效期等。

  4. 客户端解析证书并对其进行验证。如果证书不是可信机构颁布,或者证书中的域名与实际域名不一致,或者证书已经过期,就会向访问者显示一个警告,由其选择是否还要继续通信。

    如果证书没有问题,客户端就会从服务器证书中取出服务器的公钥A。然后客户端还会生成一个随机码 KEY,并使用公钥A将其加密。

  5. 客户端把加密后的随机码 KEY 发送给服务器,作为后面对称加密的密钥。

  6. 服务器在收到随机码 KEY 之后会使用私钥B将其解密。经过以上这些步骤,客户端和服务器终于建立了安全连接,完美解决了对称加密的密钥泄露问题,接下来就可以用对称加密愉快地进行通信了。

  7. 服务器使用密钥 (随机码 KEY)对数据进行对称加密并发送给客户端,客户端使用相同的密钥 (随机码 KEY)解密数据。

  8. 双方使用对称加密愉快地传输所有数据。

TCP

TCP协议又叫传输控制协议(Transport Control Protocal),是面向连接的,可靠的字节流服务。它的连接是虚连接,连接的端点是套接字(SOCKET)。它的可靠性体现在:3次握手建立连接,滑动窗口机制,一定的拥塞避免算法,流量控制,以及一定的超时重传机制。基于TCP的协议有HTTP、FTP、SMTP、TELNET、SSH、MQTT等。

服务与缓存

TCP提供的服务

TCP提供服务时需要以下计时器的支持:

  • 2MSL计时器测量一个连接处于TIME_WAIT状态的时间,四次挥手(连接释放)时有用到。
  • 重传计时器使用于当希望收到另一端的确认。超时重传、拥塞避免时有用到。
  • 坚持计时器使窗口大小信息保持不断流动,即接收端发送了接收窗口为0的报文后启动。流量控制时有用到。
  • 保活计时器可检测到一个空闲连接的另一端何时崩溃或重启。

TCP提供的服务:

  • 数据块分割:应用数据被分割成TCP认为最适合发送的数据块,由TCP传递给IP的信息单位称为报文段或段(segment)。

  • 重新排序:既然TCP报文段作为IP数据报来传输,而IP数据报的到达可能会失序,因此TCP报文段的到达也可能会失序。如果必要,TCP将对收到的数据进行重新排序,将收到的数据以正确的顺序交给应用层。

  • 全双工(Full Duplex)通信:又称为双向同时通信,即通信的双方可以同时发送和接收信息的信息交互方式。

  • 可靠传输:通过校验和、序号、确认与重传进行可靠的传输。

  • 流量控制:通过滑动窗口算法,设置接收窗口大小来进行流量控制。

  • 拥塞控制:通过慢开始&拥塞避免、快重传&快恢复算法进行拥塞控制。

不提供广播或多播的服务。

缓存

发送缓存:准备发送的数据和已发送但未收到确认的数据

img

图中红色部分为已发送但未收到确认的数据,发送缓存中的其余部分为准备发送的数据。

接收缓存:按序到达但未接受应用程序读取的数据和不按序到达的数据

img

图中接收缓存中标识“已收到”的表示按序到达但未接受应用程序读取的数据,接收窗口中的红色部分是不按序到达的数据。

TCP头部

img

  • 源端口和目的端口:各占 2 字节。端口是传输层与应用层的服务接口.传输层的复用和分用功能都要通过端口才能实现

  • 序号seq:占4字节。数据中首个字节在发送缓存中的序号。

  • 确认序号ack:占4字节。为N时表明序号N-1及之前的报文段都已经收到,期待接收序号为N的报文段。

  • 首部长度/数据偏移: 占 4 位。它指出 TCP 报文段的数据起始处距离 TCP 报文段的起始处有多远.“数据偏移”的单位是 32 位字(以 4 字节为计算单位)。

  • 紧急位URG: 为1时,紧急指针有效,紧急数据优先级更高,优先发送。

  • 确认位ACK: 为1时,确认序号ack有效,连接建立后,传送的报文段都必须把ACK置为1。

  • 推送位PSH: 为1时,接收方应该尽快将这个报文段交给应用层,不用等缓存填满,优先级更高,报文段优先交给应用层。

  • 复位RST: 为1时,表明TCP连接中出现严重差错,需要释放连接后,重建连接。

  • 同步位SYN: 为1时,用来发起/确认一个连接。

  • 终止位FIN: 为1时,表明发端完成发送任务,要求释放连接。

  • 窗口:接收窗口,即允许对方发送的数据量。

  • 检验和:检验首部+数据

  • 紧急指针:URG为1时有效,指出本报文段中紧急数据的字节数(从数据的第一个字节开始)。

  • 选项:可选如下:

    • MSS:指定TCP连接的最大传输单元大小,即每个TCP段中的最大数据量。对于TCP连接的一方,它可以通过MSS选项通知另一方自己能够接受的最大段大小。
    • 窗口扩大因子:用于扩展TCP窗口的规模,以支持更大的传输窗口,从而提高传输效率。
    • 时间戳:包含发送方的时间戳,用于测量往返时间(Round-Trip Time)和计算报文的接收时延。
    • 选择确认:接收方收到了和前面的字节流不连续的两字节。如果这些字节的序号都在接收窗口之内,那么接收方就先收下这些数据,但要把这些信息准确地告诉发送方,使发送方不要再重复发送这些已收到的数据。
  • 填充:用来确保TCP的整个首部是4字节的整数倍。

三次握手四次挥手

三次握手

img

  • 客户端发送连接请求报文段,无应用层数据。同步位SYN=1,表示请求连接。序号seq=x(随机)。确认序号无效,ACK=0,因为客户端未收到服务器端的报文段。
  • 服务器为该TCP连接分配缓存和变量,向客户端返回确认报文段,允许连接,无应用层数据。同步位SYN=1,表示确认连接。序号seq=y(随机),确认位ACK=1,确认序号有效,确认序号ack=x+1,即x+1之前的已经收到,期待接收x+1开始的报文段。
  • 客户端为该TCP连接分配缓存和变量,并向服务器端返回确认报文段,可以携带数据。同步位SYN=0,表示连接建立完毕,以后的也是0。序号seq=x+1。确认位ACK=1,确认序号ack=y+1,即y+1之前的已经收到,期待接收y+1开始的报文段。

CLOSED: 表示初始关闭状态。

LISTEN(服务器): 这个也是非常容易理解的一个状态,表示服务器端的某个SOCKET处于监听状态,可以接受连接了。

SYN-SENT: 这个状态与SYN-RCVD呼应,当客户端SOCKET执行CONNECT连接时,它首先发送SYN报文,因此也随即它会进入到了SYN-SENT状态,并等待服务端的发送三次握手中的第2个报文。SYN-SENT状态表示客户端已发送SYN报文。

SYN-RCVD(服务器): 这个状态表示接受到了SYN报文,在正常情况下,这个状态是服务器端的SOCKET在建立TCP连接时的三次握手会话过程中的一个中间状态,很短暂,基本上很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次TCP握手过程中最后一个ACK报文不予发送。当收到客户端的ACK报文后,它会进入到ESTABLISHED状态。

ESTABLISHED:这个容易理解了,表示连接已经建立了,可以发送数据。

SYN洪泛攻击:攻击者向服务器发送大量TCP连接请求,服务器确认后,攻击者不确认,造成服务器处于半连接状态,消耗了过多的资源(CPU、内存等),造成死机等问题,无法为正常用户提供服务。可使用SYN Cookie进行防御。

四次挥手

客户端和服务器端都可以终止该连接,连接结束后,主机中的资源被释放。

img

  • 客户端发送连接释放报文段,停止发送数据。结束位FIN=1,表明要释放报文段,序号seq=u,假设上一个报文段序号为u-1。
  • 服务器端回复一个确认报文段,客户到服务器这个方向的连接就释放了——半关闭状态。确认位ACK=1,序号seq=v,假设上一个报文段序号为v-1,确认序号ack=u+1。
  • 服务器端发完数据,就发出连接释放报文段,主动关闭TCP连接。结束位FIN=1,确认位ACK=1,序号seq=w(服务器端上次发送的数据序号为v~w-1),确认序号ack=u+1(因为客户端未发送数据)。
  • 客户端回复一个确认报文段。确认位ACK=1,序号seq=u+1,确认序号ack=w+1。

ESTABLISHED:建立连接成功,通信中。

CLOSE-WAIT: 表示被动关闭一方在等待关闭。当主动关闭连接的一方关闭SOCKET后发送FIN报文给被动关闭一方,被动关闭一方回应一个ACK报文给对方,此时被动关闭一方则进入到CLOSE-WAIT状态

FIN-WAIT-1:是当Socket在已经连接的状态时主动关闭连接,向对方发送了FIN报文,此时该Socket进入到FIN-WAIT-1状态。而当对方回应ACK报文后,则进入到FIN-WAIT-2状态

FIN-WAIT-2:表示半连接,挥了两次手的状态等待对方的Fin报文

TIM-WAIT:TCP协议中主动关闭连接的一方要处于TIME-WAIT状态,等待两个MSL(maximum segment lifetime)的时间后才能回到CLOSED状态,在TIME-WAIT期间仍然不能再次监听同样的server端口。

LAST-ACK: 被动关闭一方在发送FIN报 文后,最后等待对方的ACK报文。当收到ACK报文后进入CLOSED状态。

CLOSED:已经完全关闭.

服务器端收到确认报文段后关闭TCP连接。客户端等待两倍的MSL(Maximum Segment Lifetime,报文段最长寿命)时间后关闭连接,因为如果服务器端没有收到客户端回复的确认报文段会再次发出连接释放报文段,2MSL后没有收到服务器端再次发出的连接释放报文段,说明服务器端已关闭。

有限状态机

img

粗实线为客户端三次握手与四次挥手的状态转移,粗虚线为服务器端三次握手与四次挥手的状态转移。

可靠传输

校验

增加伪首部。

滑动窗口

以字节为单位的滑动窗口,大小可变。

接收窗口rwnd(recevier window):接收方根据接收缓存设置的值通知发送方,反映接收方容量。

拥塞窗口cwnd(congestion window):发送方根据自己估算的网络拥塞程度而设置的窗口值,反应网络当前容量。初始值IW根据SMSS(SENDER MAXIMUM SEGMENT SIZE,发送方最大报文段大小,不包含TCP头部)来设定。

发送窗口 = Min{接收窗口rwnd,拥塞窗口cwnd}

确认与重传

累计确认与超时重传

超时重传:TCP发送方在规定的时间(重传时间,使用重传计时器)内没有收到确认就要重传已发送的报文段。【重传时间:采用自适应算法,动态改变重传时间RTTs(加权平均往返时间)。RTT(round-trip time)为数据完全发送完(交给发送方IP层)到收到确认信号的时间。】

累积确认:无论丢失了多少接收方返回的确认,对于发送发方来说,只要是在发送方超时时间之内成功接到了接收方返回的一串应答中的最后一个,则包含了前面全部的确认信息。 从这个角度看,实际上累积确认的目的是为了避免一系列应答中的某个应答丢失造成的无必要的重传。

超时重传解决的是传输可靠性问题,累计确认是为了更快速的传输。

冗余确认与快速重传

冗余确认:TCP接收方已经发送过的确认报文段。由于收到了比确认报文段所期待的报文段序号更大的报文段,而未收到确认报文段所期待的报文段,则再次发送确认报文段。

冗余确认是原因可能是乱序到达和丢包,两次的话可能是乱序到达造成的,三次的话绝大部分是丢包了,需要快速重传。

快速重传:TCP发送方在未达到重传时间时收到接收方的冗余确认(三个重复的)就要重传已发送的报文段。

流量控制

在通信过程中,接收方根据自己接收缓存的大小,动态地调整发送方的发送窗口大小,即接收窗口rwnd(接收方设置确认报文段的窗口字段来将rwnd通知给发送方),发送方的发送窗口取接收窗口rwnd和拥塞窗口cwnd的最小值

eg.

开始时,B通知A“老弟,我的接收窗口是400”。

img

注:填充黄色的为发送方A的发送窗口,绿色字体代表已发送的数据(接收方不一定接收,看ack)。

最后,B通知A接收窗口为0,这时,B可能在忙着给应用层传输数据。

那么,什么时候A可以再给B发送数据呢?需要B再次给A发送一个报文段,通知A“老弟,你可以发送数据了,rwnd=xxx”。

但是,假如B发送的这个报文,A没有收到,这时A等待B通知,B等待A发送数据,就会死锁。为了解决这个问题,需要使用坚持计时器。

在发送方收到接收方的rwnd=0时,坚持计时器启动。坚持计时器到期,发送方发送零窗口探测报文段(仅1字节),询问接收方“老哥,你还不接收数据吗?”,如果B给A发送过了通知,这时接收到发送方的探测报文段,就知道它的通知丢失了,A没有收到,就会再发送通知,A接收到后继续发送数据,双方正常通信。

注:TCP规定,即使设置为零窗口,也必须接收以下几种报文段:零窗口探测报文段、确认报文段和携带紧急数据的报文段。

拥塞控制

假设:数据单方向传送,另一方向只传送确认,发送方接到确认后增加拥塞窗口大小。接收方有足够大的缓存空间,发送窗口取决于拥塞程度,即发送窗口=拥塞窗口。

为了讨论方便,纵坐标的单位为最大报文段,长度为MSS。横纵标单位为发送了一批报文段并收到他们确认的时间,即往返时延RTT。

下面的算法,可查看[RFC 5681](RFC 5681 - TCP Congestion Control (ietf.org))

慢开始和拥塞避免

ssthresh(slow start thresh):慢开始阈值,达到后“加法增大”。

乘法减小:新的ssthresh为上次拥塞状态下拥塞窗口的一半,RFC 5681中写的是ssthresh = max (FlightSize / 2, 2*SMSS),我们这里就直接采用FlightSize / 2了。

慢开始:起始值特别低,例如1,倍增,超时后回到起始值。

拥塞避免:达到ssthresh后,加法增大。达到网络拥塞状态后,拥塞窗口回归到慢开始状态即初始值。

img

开始值为1,未达到ssthresh前,执行慢开始算法,倍增,1、2、4、8、16;达到ssthresh,执行拥塞避免算法,加法增大,17、18、19、…、24,超时,新的ssthresh=24/2=12,回到1,后续类似。

快重传与快恢复

快速重传:TCP发送方在未达到重传时间时收到接收方的冗余确认(三个重复的,加上之前收到的,共4个一样的ack)就要重传已发送的报文段。

快恢复:达到网络拥塞状态后,拥塞窗口不是回归到初始状态,而是从新的ssthresh(原来的减半)开始,加法增大

img

开始值为1,未达到ssthresh前,执行慢开始算法,倍增,1、2、4、8、16;达到ssthresh,执行拥塞避免算法,加法增大,17、18、19、…、24,收到3个重复的确认,新的ssthresh=24/2=12,回到新的ssthresh即12,后续类似。