Blog

Yoki


  • 首页

  • 归档

  • 搜索

css中的四种fc(格式上下文)

发表于 2018-05-28

什么是 FC

formatting context 的缩写,格式上下文

  • 是 css2.1 的一个规范
  • 是页面中的一块渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和相互作用
  • css2.1 定义了两个格式上下文
    • BFC(block)
    • IFC(inline)
  • css3 定义了两个格式上下文
    • GFC(grid)
    • FFC(flex)

概念

  • block-level boxes:display 属性值为’block’,‘list-item’,‘table’会生成一个 block-level box,这样盒子会参与到 bfc(一种布局方式)中
  • containing block:在浏览器内,想要把一个元素画出来,至少要知道定位和尺寸。定位有三种,无论哪一种都要先找到所在的 containing block,相当于一个大箱子里面摆很多小盒子,小盒子怎么摆取决于大箱子

BFC

是一个独立的渲染区域,只有 block-level boxes 参与,规定了内部的 block-level box 如何布局,并且与这个区域外部毫不相干。

布局规则

  • 内部的 box 会在垂直方向一个接着一个的放置
  • box 垂直方向的距离由 margin 决定,属于同一个 BFC 的两个相邻 box 的 margin 会发生重叠
  • bfc 的区域不会与 float box 重叠(可以用来实现两栏布局)
  • bfc 就是页面上一个隔离的独立容器,容器里面的子元素不会影响到外面的元素

如何触发

  • 根元素(body)
  • float 属性不为 none
  • position 为 abs 或者 fixed
  • display 为 inline-block, table-cell, table-caption(表格相关的)
  • 在 BFC 中,每一个盒子的左外边缘(margin-left)会触碰到容器的左边缘(border-left)(对于从右到左的格式来说,则触碰到右边缘)
  • overflow 不为 visible

推荐阅读

  • 理解 BFC 的原理及其作用
  • 深入理解 BFC 和 Margin Collapse
  • 理解 css 中的 bfc

IFC

内联格式化上下文

如何触发

  • 元素满足 inline-level box

布局特点

  • 与 BFC 的区别是,水平方向的
  • 内部元素全是 inline-level
  • 如果由一个子节点是 block-level,父节点就要生成 BFC,但是 inline 元素怎么放进 BFC(浏览器会生成匿名盒子来容纳这些 inline 元素)
  • IFC 中时不可能有块级元素的,当插入块级元素时(如 p 中插入 div)会产生两个匿名块与 div 分隔开,即产生两个 IFC,每个 IFC 对外表现为块级元素,与 div 垂直排列。
  • 每一行的多个内联元素都会生成同一个 line-box(线框)
  • 计算行框里的各行内级框的高度。对于置换元素、行内块元素、行内表格元素来说,这是边界框的高度,对于行内框来说,这是其 ‘line-height’。

具体作用

  • 水平居中:当一个块要在环境中水平居中时,设置其为 inline-block 则会在外层产生 IFC,通过设置父容器 text-align:center 则可以使其水平居中。
  • 垂直居中:创建一个 IFC,用其中一个元素撑开父元素的高度,然后设置其 vertical-align:middle,其他行内元素则可以在此父元素下垂直居中。

推荐阅读

  • 浅析 CSS 中的 BFC 和 IFC
  • line box,inline box 及 vertical-align 分析

读《图解算法》06-狄克斯特拉算法

发表于 2018-05-27

为什么有狄克斯特拉算法

这里的时间,换句话,我们给边加上了权重

  • 之前 BFS 求出了最短路径,那么如果我们给边加上了时间呢?
  • 发现最短路径并不是最快路径

步骤

  • 找出最便宜的节点,就是说可以在最短时间内到达的节点(算法关键)
  • 更新该节点的邻居的开销,检查是否有前往他们的更短路径,有就更新
  • 重复这个过程,直到对图中的每个节点都这样做了
  • 计算最终路径

术语

  • 权重:狄克斯特拉算法用于每条边都有关联数字的图,这些关联数字叫做权重
  • 带权重的图叫做加权图,计算最短路径用狄克斯特拉算法
  • 不带权重的叫非加权图,计算最短路径用广度优先搜索
  • 图还可能有环
  • 负权边:权重是负的。
  • 有负权边的情况,不能使用狄克斯特拉算法。因为该算法这样假设:对于处理过的节点,没有前往该节点的更短路径,只要在没有负权边才成立。应该使用贝尔曼-福德算法。

算法实现

  • 需要三个散列表
    • 图的散列表
    • 节点的开销的散列表
    • 存储父节点的散列表
  • 需要一个数组,用于记录处理过的节点,不用多次处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//如何表示加权图
graph = {};
graph["start"] = {};
graph["start"]["a"] = 6;
graph["start"]["b"] = 2;
graph["a"] = {};
graph["a"]["fin"] = 1;
graph["b"] = {};
graph["b"]["a"] = 3;
graph["b"]["fin"] = 5;
graph["fin"] = {}; //终点没有任何邻居
//开销表
costs = {};
costs["a"] = 6;
costs["b"] = 2;
costs["fin"] = infinity;

//父节点表
parents = {};
parents["a"] = "start";
parents["b"] = "start";
parents["fin"] = None;
//算法
node = find_lowest_cost_node(costs) //在未处理的节点中找出开销最小的节点
while node is not None: //←------这个while循环在所有节点都被处理过后结束
cost = costs[node]
neighbors = graph[node]
for n in neighbors.keys(): //←------遍历当前节点的所有邻居
new_cost = cost + neighbors[n]
if costs[n] > new_cost: //←------如果经当前节点前往该邻居更近,
costs[n] = new_cost //←------就更新该邻居的开销
parents[n] = node //←------同时将该邻居的父节点设置为当前节点
processed.append(node) //←------将当前节点标记为处理过
node = find_lowest_cost_node(costs) //←------找出接下来要处理的节点,并循环
//找出最便宜的节点且没处理过的函数
def find_lowest_cost_node(costs):
lowest_cost = float("inf")
lowest_cost_node = None
for node in costs: // ←------遍历所有的节点
cost = costs[node]
if cost < lowest_cost and node not in processed: //←------如果当前节点的开销更低且未处理过,
lowest_cost = cost // ←------就将其视为开销最低的节点
lowest_cost_node = node
return lowest_cost_node

读《图解算法》05-广度优先搜索

发表于 2018-05-27

广度优先算法简单介绍

breadth-first search ,以下简称 BFS

  • 能让你找出两样东西之间的最短距离,不过最短距离的含义有很多。

可以干什么(感受一下多强大)

  • 编写国际跳棋 AI,计算最少走多少就可以获胜
  • 根据人际关系网络找到关系最近的医生

可以回答两类问题

  • 从节点 A 出发,有前往节点 B 的途径吗
  • 从节点 a 出发,前往节点 b 的路径哪条最短

如何实现

  • 创建一个队列,存储要检查的人
  • 从队列弹出一个人,检查这个人是否是想要的,不是的话,把这个人的邻居加入队列
  • 假设队列里面肯定有重复的,所以要将检查的人标记,不能检查两次,不然会出现无限循环的情况
  • 可以专门存一个数组来记录检查过的人,或者用散列表存储,本质去掉重复

运行时间

  • 在整个人际关系网找到正确的,意味着要沿每条边前行,因此运行时间为 O(n)
  • 还使用了队列,其中要包含每个检查的人。将一个人添加到队列是 O(1),n 个人就是 O(n)
  • 所以运行时间通常为 O(V+E),v 为定点数,e 为边数

图

简介

想象以下场景

  • 从我家到公园,需要几步,求最短路径
  • 一个欠钱的关系图,几个人之间的

组成

  • 图是由节点和边组成。
  • 图用于模拟不同的东西是如何相连的

有向图和无向图

  • 有向图的关系是单向的,从节点 a 到节点 b,但不能反过来
  • 无向图直接相连

查找算法

  • 有序列表的查找算法有二分法,同样,图的查找算法是广度优先搜索

如何实现图

  • 因为图是由多个节点组成,每个节点都与邻近节点相连,怎么表示我->bob 这样的关系,可以使用散列表,将 key 映射到 value
  • 这里我们将节点映射到所有邻居
  • 图不过是一系列的节点和边的组合
1
2
3
4
5
let graph = {};
graph["me"] = ["alice", "bob"];
graph["bob"] = ["peggy"];
graph["alice"] = ["peggy"];
graph["peggy"] = [];

队列

和生活中的队列完全一样

  • 是一个先进先出的数据结构
  • 队列只支持两种操作:入队和出队

树

特殊的图,没有往后指的边,自上而下

  • 假设正在规划一场婚礼,并有一个很大的图
  • 其中充满着需要做的事,但是却不知道从何开始
  • 可以使用拓扑排序来创建一个有序列表

读《图解算法》04-散列表(hash table)

发表于 2018-05-27

为什么散列表会出现

  • 场景:如果超市买东西结账的时候,售货员在一个本子里查找价格
  • 如果是有序的(二分查找)还好,时间是 O(logn),如果是无序(简单查找)的话,那就是 O(n)
  • 如果直接有一个 O(1)的查找速度就好了

散列函数

将输入映射到数字

  • 一致性:输入 apple 时得到的是 4,那么每次输入 apple 都必须是 4
  • 不同性:不同的输入将得到不同的输出。如果输入 apple 和 yoki 都得到 4,那么这是一个不好的散列函数。

创造散列表

结合散列函数和数组

  • 创建一个空数组
  • apple 输入到散列函数,输出 3,然后把 apple 的价格存储到数组索引 3
  • 接着各个类推,知道存完数组
  • 然后我们要找 apple 的价格,就把 apple 输入交给散列函数,得到 3 去数组里面找

散列表的经典应用

查找,防止重复,用于缓存

查找

  • 被用于大海捞针的查找
  • 这个就不用细说了,类似的有 dns 解析

防止重复

场景:负责一个投票站,每个人只能投一票,如何避免重复投票

  • 有一个方法是:有人来投票,就将它记录在一个投票名单里面,然后接下来的人都遍历这个投票名单,如果有就不能投票,但是这样就列表会越来越长,就会变慢
  • 另外一种就是散列表,超快

缓存

  • 浏览器缓存的数据存储在散列表里面
  • 如果访问 facebook 的页面,会先检查散列表中是否存储了该页面
  • 如果不在缓存中,才去访问服务器,然后把数据放到缓存里,这样下次有人访问就可以直接命中缓存

冲突

事实上不可能不同的输入都能获得不同的值

  • 假设有一个数组包含 26 个位置,而我们使用的散列函数非常简单,按照字母表顺序分配位置
  • apple 第一个,bear 第二个,接下来来了一个 banana,理应分到第二个,但是这个时候第二个位置已经是 bear 了
  • 这个就叫冲突,解决冲突的办法有很多,简单的就是在这个冲突的位置存储一个链表,bear 末尾的指针指向 banana
  • 所以散列函数很重要,好的散列函数将 key 均匀的映射到散列表的不同位置

如何避免冲突

  • 较低的填装因子
    • 散列表包含的元素数:位置总数就是填装因子
    • 越小越好,满了只能调整长度,换一个更长的数组
    • 一个不错的经验规则就是,一旦填装因子大于 0.7,那么就要调整散列表的长度
  • 良好的散列函数
    • SHA 函数s

散列表性能如何

平均情况

  • 查找,插入,删除都是 O(1),常量时间

最糟糕情况

  • 查找,插入,删除都是 O(n),线性时间

为什么会有两种情况,这是因为有了冲突可能会靠链表解决,n 个长度的链表,最好情况下没有冲突,就常量时间

浅谈同构(CSR+SSR)

发表于 2018-05-24

什么是同构

维基百科:在抽象代数中,同构(英语:isomorphism)指的是一个保持结构的双射。在更一般的范畴论语言中,同构指的是一个态射,且存在另一个态射,使得两者的复合是一个恒等态射。

  • 一套代码既可以在服务端运行,又可以在客户端运行,这就是同构应用。
  • 服务端直出(html 字符串)和客户端渲染的组合,能够充分结合两者的优势,并有效避免两者的不足。
  • 具备单页应用和多页应用的所有优势

服务端渲染和客户端渲染

以下叫做 SSR 和 CSR

  • ssr 的话,服务器返回的结构相对完整的 html 文件,通过解析 html 文件,浏览器就可以渲染出来页面。
  • csr 的话,拿到的只是包含 js 代码的 html 文件,在浏览器渲染页面之前,需要动态创建 html 标签

CSR 的优势

即单页应用的优势

  • 局部刷新。不用每次都进行完整页面请求。
  • 懒加载。如在页面初始的时候可以只加载可视区域内的数据,滚动后加载别的。
  • 富交互。js 实现各种炫酷效果。
  • 节约服务器成本。省电省钱。

SSR 的优势

  • 不需要下载一堆 js 和 css 后才能看到首页(首屏性能)
  • SEO
  • 对于电量不给力的手机,减少在客户端的电量消耗

推荐阅读

  • “服务端渲染”吊打“客户端渲染”的那些事

为什么要同构

  • 通过 Node 直出,将传统的三次 http 请求简化成一次 http 请求,降低首屏渲染时间
  • seo:服务端渲染对搜索引擎的爬取有着天然的优势

同构的实现策略

要实现同构,首先要正视一点,全盘同构是没有意义的。服务器端和浏览器端是两个不同的平台和环境,他们专注于解决各自的问题。

  • 能够同构的代码,直接复用
  • 无法同构的代码,封装成形式同构(具体看react 同构与性能极致优化)
    • 比如 User-Agent 字符串,浏览器端直接 navigation.userAgent,服务器端需要 req.get(‘user-agent’)

同构并没有想象中那么美

框架可以尽力帮我们做好,比如 next.js

  • 性能:把原来放在几百万浏览器端的工作拿过来给服务器端做,计算力大。个性化的缓存,可以把每个用户个性化信息缓存到浏览器,这是一个天生的分布式缓存系统。
  • 不容忽视的服务器端和浏览器环境差异:dom api 在客户端找不到等
  • 内存溢出:前端代码由于浏览器环境刷新一遍内存重置的天然优势,对内存溢出没有充分考虑。
  • 异步操作:前端可以做非常复杂的请求合并和延迟处理

推荐阅读

  • 精读前后端渲染之争
  • 同构 mvc 的前端实践
  • react 同构与性能极致优化
  • 解密 Vue SSR

前端性能之用户可操作时间

发表于 2018-05-23

官方的一个浏览器从打开一个页面内部的一系列状态

  • 用 performance.timing 的 api 就可以获取到各个阶段的
  • 一般 start 和 end 间包括一个阶段
  • 具体可以观察推荐阅读的那张图
  • navigationStart 到 responseEnd 之间是网络传输层面
  • domLoading 到 domComplete 是服务器传输回字节后浏览器的各种事件状态
    • domLoading
    • domInteractive(dom tree 构建完成)
    • domContentLoadedEventStart(触发的是 domContentLoaded 事件,这个很重要,network 都有体现)
    • domContentLoadedEventEnd
    • domComplete(资源全部加载完成,包括异步 js)
    • loadEventStart(触发 load 事件)
    • loadEventEnd

用户可操作时间

用户可以进行正常的事件输入交互操作

  • 就是 domContentLoadedEventEnd-navigationStart 的时间
  • jq 的$()就是指 domContentLoaded 事件

一些知识点

  • document 到达 domInteractive 状态的时候,代表 dom 树的构建完成
  • 浏览器拿到文档首字节之后,也就是 responseEnd 之后。浏览器将 html 解析并构建成 DOM tree,同时将 css 解析成 cssom,这个过程是同步的
  • 如果有 js 参与,因为同步的 js 可以改写文档在任何节点,所以 domtree 一旦碰上同步的 script 标签就会停止构建
  • js 能查询 dom 对象的可被计算的样式,cssom 构建完之后才轮到 js 执行,但是这是指 css 文件在 js 之前,如果 css 在 js 之后,不会阻塞 js

推荐阅读

  • 前端性能的几个基础指标

白屏和首屏时间

发表于 2018-05-22

白屏时间

浏览器开始显示内容的时间。从我们输入网址,到浏览器出现第一个字符的时间

  • chrome 有自己的 api,window.chrome.loadTimes().firstPaintTime * 1000 - window.performance.timing.navigationStart

如何计算

通常认为浏览器开始渲染 body 标签或者解析完 head 标签的时刻就是页面白屏结束的时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>白屏</title>
<script type="text/javascript">
// 不兼容performance.timing 的浏览器,如IE8
window.pageStartTime = Date.now();
</script>
<!-- 页面 CSS 资源 -->
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
<script type="text/javascript">
// 白屏时间结束点
window.firstPaint = Date.now();
</script>
</head>
<body>
<!-- 页面内容 -->
</body>
</html>
  • 如果可以使用 performance api 的时候,白屏时间=firstPaint - performance.timing.navigationStart(浏览器打开网站开始)
  • 如果不可以使用,比如 ie8,那么白屏时间= firstPaint - pageStartTime

首屏时间

指用户打开网站开始,到浏览器首屏内容渲染完成的时间。一般来说,5s 内优秀,10 之内可以接受,10s 以上不可以接受

怎么计算

1.首屏模块标签标记法,2.统计首屏内加载最慢的图片的时间,3.自定义首屏内容计算法

首屏模块标签标记法

  • 适用于首屏内容不需要通过拉取数据才能生存以及页面不考虑图片等资源加载的情况。
  • 但是现在大多数情况都需要通过接口拉数据才能完整显示,所以这个不太使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首屏</title>
<script type="text/javascript">
window.pageStartTime = Date.now();
</script>
<link rel="stylesheet" href="common.css">
<link rel="stylesheet" href="page.css">
</head>
<body>
<!-- 首屏可见模块1 -->
<div class="module-1"></div>
<!-- 首屏可见模块2 -->
<div class="module-2"></div>
<script type="text/javascript">
window.firstScreen = Date.now();
</script>
<!-- 首屏不可见模块3 -->
<div class="module-3"></div>
<!-- 首屏不可见模块4 -->
<div class="module-4"></div>
</body>
</html>

统计首屏内图片完成加载的时间

  • 通常首屏内容加载最慢的就是图片资源,因此我们会把首屏内加载最慢的图片的时间当作首屏时间
  • 遍历首屏内所有图片标签,并且监听所有图片标签的 onload 事件,最终遍历图片标签的加载时间的最大值,然后用这个最大值减去 navigationStart

自定义模块内容计算法

  • 由于统计图片加载时间比较复杂,通常会自定义模块内容,来简化
  • 忽略图片等资源加载情况,只考虑页面主要 dom
  • 只考虑首屏的主要模块,而不是严格意义首屏线上的所有内容

推荐阅读

  • 7 天打造前端性能监控系统

HTTP/2的学习

发表于 2018-05-22

HTTP/1.0 的通信

  • 每完成一次请求和响应,TCP 连接就会断开。

HTTP/1.1 的通信

  • TCP 连接有 RTT(Round Trip Time,就是往返时延的),每次请求一个资源就要有一次 RTT,用户可是等不得这种慢节奏的响应。
  • 到了 1.1,tcp 可以持久连接了,请求同域名下的 n 个资源,可以节约(n-1)*rtt 的时间
  • http 管道技术虽然实现了客户端向服务器并行发送多个请求,但是 1.1 有严格的串行返回机制(前一个响应没有完成,下一个响应就不能返回),如果第一个响应时间很长,那么后面的响应处理完了也没法发送,只能被缓存起来,占用服务器内存。

SPDY

  • 谷歌推出的传输协议,最终演变成 HTTP/2

HTTP/2.0

二进制分帧层,多向请求与响应,优先级与依赖性,首部压缩,服务器推送

二进制分帧层

  • tcp 连接在客户端和服务器间建立了一条运输的通道,可以双向通信
  • 当一端要向另一端发送消息的时候,把这个拆成几部分(帧),然后通过发起一个流来对这些帧进行发送,最后在另一端将同一个流的帧组合
  • 就好比搬家,先把桌子拆成零件,再通过几次的搬运,到了新家,再把桌子重新拼装起来

多向请求与响应(多路复用)

  • 一端发送消息会先对消息进行拆分,与此同时,也会给同一个消息拆分出来的帧带上一个编号(stream ID),这样另一端接受这些帧后就可以根据编号进行组合

优先级和依赖性

  • 流可以有一个优先级属性

首部压缩

  • 在客户端和服务器各自维护一个首部表,表中用索引代表首部名,上一次发送,两端都会记住已发送哪些首部,下一次传输只用传输差异的数据,相同的数据直接用索引表示即可。

服务器推送

  • 服务器可以对一个客户端请求发送多个响应,也就是说,除了对最初请求的响应外,服务器还可以额外向客户端推送资源

由上可得 http/2

  • 通过二进制分帧和多路复用机制,有效解决了 1.x 下请求/响应延迟的问题
  • 新的首部压缩技术使得 1.x 首部信息臃肿的问题得到解决
  • 优先级和依赖性与服务器推送使得我们可以更有效地利用好这个单一的 tcp 连接

推荐阅读

  • http/2 安利篇(一)
  • http/2 优化篇(二)
  • 谷歌的 http2 学习篇

TCP/IP学习(二)

发表于 2018-05-22

TCP 和 IP 协议

IP(Internet Protocol 网际协议)

  • 是计算机用来相互识别的通信的一种机制,每台计算机都有一个 ip 来识别在 internet 上的位置
  • ip 协议仅仅是允许计算机相互发消息,但是它并不检查消息是否以发送的次序到达而且没有损坏
  • 为了提供消息校验功能,直接在 IP 协议上设置 TCP

TCP(Transmission Control Protocol 传输控制协议)

  • 保证数据包以正确序列到达,并且尝试确认数据包的内容没有改变
  • tcp 在 ip 地址之上引端口,允许计算机通过网络提供各种服务
  • 用于从应用程序到网络的数据传输控制,而 ip 负责计算机间的通信

HTTP 工作过程

一次 HTTP 操作称作一个事务

  • 地址解析
    • 从地址分解出协议名,主机名,端口
    • 需要 DNS 解析域名,得到主机的 ip 地址
  • 封装 HTTP 请求数据包
  • 封装成 TCP 包,建立 TCP 连接(三次握手)
    • 在 http 工作之前,首先要通过网络与服务器建立连接,该连接通过 tcp 完成
    • http 是比 tcp 更高层次的应用层协议,更具规则,只有低层次协议建立之后,才能进行更高层协议的连接
  • 发送 http 请求
  • 服务器响应
  • 服务器关闭 TCP 连接
    • 如果加入了长连接(keep-alive),tcp 连接仍然保持打开状态,减少建立新连接所需的时间,还节约了带宽

HTTPS 的 TLS/SSL

TLS 全称是 transport layer security(安全传输层协议)

主要作用

  • 对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全
  • 对网站服务器进行真实身份认证

依赖的基本算法

主要是三类

  • 散列函数验证信息的完整性
  • 对称加密算法采用协商好的秘钥对数据加密
  • 非对称加密实现身份认证和密钥协商

推荐阅读

  • HTTP 和 HTTPS 详解

TCP/IP学习(一)

发表于 2018-05-21

TCP/IP 概念层模型

对比的是 OSI 七层模型

  • 应用层(http)
  • 传输层(tcp)
  • 网络层(ip)
  • 链路层(以太网)

数据包

网络中传输的数据包由两部分组成,一个是协议所要用到的首部,另一部分是上一层传过来的数据。

  • 首部,明确标明了协议应该如何读取数据,就像协议的脸。

传输层协议

具有代表性的两个,分别是 tcp 和 udp

TCP

  • 面向连接的,可靠的协议。
  • 为提供可靠性传输,提供顺序控制和重发控制。

UDP

  • 不具有可靠性的数据报协议
  • 实时性要求高

端口号

一台计算机上可以同时运行多个程序。传输层协议正是利用这些端口号识别本机中正在进行通信的应用程序。

  • 数据链路层,指的是 mac 地址,用于识别统一链路中不同的计算机。
  • 网络层,指的是 ip 地址,用于识别 tcp/ip 网络中互联的主机和路由器
  • 传输层,指的是端口号,用于识别同一计算机中进行通信的不同应用程序。被称为程序地址。

端口号的确定

标准既定的端口号

  • 每个应用程序都有其指定的端口号,但不是说随意使用任何一个端口号。例如 http,ftp 所使用的端口号就是固定的,这些叫知名端口号。
  • 知名端口号分布在 0-1023
  • 此外还有一些端口号被正式注册,他们分布在 1024-49151 之间,可用于任何通信用途

时序分配法

  • 服务器有必要确定监听端口号,但是接受服务的客户端没必要确定端口号
  • 客户端应用程序全权交由操作系统设置

TCP 的三次握手

建立连接

  • 第一次握手:客户端将标志位 SYN 置为 1,随机产生一个值 seq=J,并将该数据包发送给服务器端,客户端进入 SYN_SENT 状态,等待服务器端确认。
  • 第二次握手:服务器端收到数据包后由标志位 SYN=1 知道客户端请求建立连接,服务器端将标志位 SYN 和 ACK 都置为 1,ack=J+1,随机产生一个值 seq=K,并将该数据包发送给客户端以确认连接请求,服务器端进入 SYN_RCVD 状态。
  • 第三次握手:客户端收到确认后,检查 ack 是否为 J+1,ACK 是否为 1,如果正确则将标志位 ACK 置为 1,ack=K+1,并将该数据包发送给服务器端,服务器端检查 ack 是否为 K+1,ACK 是否为 1,如果正确则连接建立成功,客户端和服务器端进入 ESTABLISHED 状态,完成三次握手,随后客户端与服务器端之间可以开始传输数据了。

TCP 的四次挥手

中断连接端可以是客户端,也可以是服务器端。

  • 第一次挥手:客户端发送一个 FIN=M,用来关闭客户端到服务器端的数据传送,客户端进入 FIN_WAIT_1 状态。意思是说”我客户端没有数据要发给你了”,但是如果你服务器端还有数据没有发送完成,则不必急着关闭连接,可以继续发送数据。
  • 第二次挥手:服务器端收到 FIN 后,先发送 ack=M+1,告诉客户端,你的请求我收到了,但是我还没准备好,请继续你等我的消息。这个时候客户端就进入 FIN_WAIT_2 状态,继续等待服务器端的 FIN 报文。
  • 第三次挥手:当服务器端确定数据已发送完成,则向客户端发送 FIN=N 报文,告诉客户端,好了,我这边数据发完了,准备好关闭连接了。服务器端进入 LAST_ACK 状态。
  • 第四次挥手:客户端收到 FIN=N 报文后,就知道可以关闭连接了,但是他还是不相信网络,怕服务器端不知道要关闭,所以发送 ack=N+1 后进入 TIME_WAIT 状态,如果 Server 端没有收到 ACK 则可以重传。服务器端收到 ACK 后,就知道可以断开连接了。客户端等待了 2MSL 后依然没有收到回复,则证明服务器端已正常关闭,那好,我客户端也可以关闭连接了。最终完成了四次握手。

推荐阅读

  • tcp/ip 协议篇二
1234…9
Yoki

Yoki

云在青天水在瓶

82 日志
21 标签
© 2019 Yoki
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.4