diff --git a/README.md b/README.md index 7ae8492f..f16b8eb5 100644 --- a/README.md +++ b/README.md @@ -133,15 +133,39 @@ Google 开源项目的代码风格规范。 > [Download](https://github.com/CyC2018/Interview-Notebook/blob/master/other/download.md) +一些 PDF 书籍。 + ## 后记 :memo: -> [Postface](https://github.com/CyC2018/Interview-Notebook/blob/master/other/postface.md) +**关于仓库** - +因为大部分内容是笔者一个字一个字打上去的,所有难免会有一些笔误。如果发现,可以直接在相应的文档上编辑修改。 + +笔者能力有限,很多内容还不够完善。如果您希望和笔者一起完善这个仓库,可以在发表一个 Issue,表明您想要添加的内容,笔者会及时查看。 + +因为不打算将这个仓库做成一个大而全的面试宝典,只希望添加一些比较通用的基础知识,或者是与 Java 和分布式相关的内容,但是不添加 Java Web 相关的内容。 + +您也可以在 Issues 中发表关于改进本仓库的建议。 + +**关于上传** + +笔者在本地使用为知笔记软件进行书写,为了方便将本地笔记内容上传到 Github 上,实现了一整套自动化上传方案,包括文本文件的导出、提取图片、Markdown 文档转换、Git 同步。 + +进行 Markdown 文档转换是因为 Github 使用的 GFM 不支持 MathJax 公式和 TOC 标记,所以需要替换 MathJax 公式为 CodeCogs 的云服务和重新生成 TOC 目录。这里提供了笔者实现的 GFM 文档转换工具的下载:[GFM-Converter](https://github.com/CyC2018/GFM-Converter)。 + +**关于排版** + +笔记内容按照 [中文文案排版指北](http://mazhuang.org/wiki/chinese-copywriting-guidelines/#%E4%B8%8D%E8%A6%81%E4%BD%BF%E7%94%A8%E4%B8%8D%E5%9C%B0%E9%81%93%E7%9A%84%E7%BC%A9%E5%86%99) 进行排版,以保证内容的可读性。这里提供了笔者实现的中英混排文档在线排版工具:[Text-Typesetting](https://github.com/CyC2018/Markdown-Typesetting),目前实现了加空格的功能,之后打算实现对英文专有名词提示首字母大写的功能。 + +不使用 `![]()` 这种方式来引用图片是为了能够控制图片以合适的大小显示。而且 GFM 不支持 `
![]()
` 让图片居中显示,只能使用 `
` ,所以只能使用 img 标签来引用图片。 + +**关于转载** + +本仓库内容使用到的资料都会在最后面的参考资料中给出引用链接,希望您在使用本仓库的内容时也能给出相应的引用链接。 ## License diff --git a/notes/Git.md b/notes/Git.md index 2041b8f5..1695faad 100644 --- a/notes/Git.md +++ b/notes/Git.md @@ -79,7 +79,7 @@ Git 把每次提交都连成一条时间线。分支使用指针来实现,例 # 冲突 -当两个分支都对同一个文件进行了修改,在分支合并时就会产生冲突。 +当两个分支都对同一个文件的同一行进行了修改,在分支合并时就会产生冲突。

diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md index cf67cdca..7e5916ec 100644 --- a/notes/Leetcode 题解.md +++ b/notes/Leetcode 题解.md @@ -188,7 +188,7 @@ Input: [1,2], [1,2,3] Output: 2 Explanation: You have 2 children and 3 cookies. The greed factors of 2 children are 1, 2. -You have 3 cookies and their sizes are big enough to gratify all of the children, +You have 3 cookies and their sizes are big enough to gratify all of the children, You need to output 2. ``` @@ -420,7 +420,7 @@ public int[][] reconstructQueue(int[][] people) { 双指针主要用于遍历数组,两个指针指向不同的元素,从而协同完成任务。 -**从一个已经排序的数组中查找出两个数,使它们的和为 0** +**从一个已经排序的数组中找出两个数,使它们的和为 0** [Leetcode :167. Two Sum II - Input array is sorted (Easy)](https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/description/) @@ -518,7 +518,7 @@ Output: True Explanation: You could delete the character 'c'. ``` -题目描述:字符串可以删除一个字符,判断是否能构成回文字符串。 +题目描述:可以删除一个字符,判断是否能构成回文字符串。 ```java public boolean validPalindrome(String s) { @@ -548,7 +548,7 @@ private boolean isPalindrome(String s, int l, int r){ [Leetcode : 88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/) -题目描述:把归并结果存到第一个数组上 +题目描述:把归并结果存到第一个数组上。 ```java public void merge(int[] nums1, int m, int[] nums2, int n) { @@ -596,7 +596,7 @@ Output: "apple" ``` -题目描述:可以删除 s 中的一些字符,使得它成为字符串列表 d 中的一个字符串。要求在 d 中找到满足条件的最长字符串。 +题目描述:删除 s 中的一些字符,使得它构成字符串列表 d 中的一个字符串,找出能构成的最长字符串。如果有多个相同长度的结果,返回按字典序排序的最大字符串。 ```java public String findLongestWord(String s, List d) { @@ -632,7 +632,7 @@ public String findLongestWord(String s, List d) { [Leetocde : 215. Kth Largest Element in an Array (Medium)](https://leetcode.com/problems/kth-largest-element-in-an-array/description/) -**排序** :时间复杂度 O(nlgn),空间复杂度 O(1) 解法 +**排序** :时间复杂度 O(nlgn),空间复杂度 O(1) ```java public int findKthLargest(int[] nums, int k) { @@ -706,7 +706,7 @@ public int findKthLargest(int[] nums, int k) { ### 桶排序 -**找出出现频率最多的 k 个数** +**出现频率最多的 k 个数** [Leetcode : 347. Top K Frequent Elements (Medium)](https://leetcode.com/problems/top-k-frequent-elements/description/) @@ -714,6 +714,8 @@ public int findKthLargest(int[] nums, int k) { Given [1,1,1,2,2,3] and k = 2, return [1,2]. ``` +设置若干个桶,每个桶存储出现频率相同的数,并且桶的下标代表桶中数出现的频率,即第 i 个桶中存储的数出现的频率为 i。把数都放到桶之后,从后向前遍历桶,最先得到的 k 个数就是出现频率最多的的 k 个数。 + ```java public List topKFrequent(int[] nums, int k) { List ret = new ArrayList<>(); @@ -747,28 +749,42 @@ public List topKFrequent(int[] nums, int k) {

-广度优先搜索的搜索过程有点像一层一层地进行遍历:从节点 0 出发,遍历到 6、2、1 和 5 这四个新节点。 +广度优先搜索的搜索过程有点像一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个长度。需要注意的是,遍历过的节点不能再次被遍历。 -继续从 6 开始遍历,得到节点 4 ;从 2 开始遍历,没有下一个节点;从 1 开始遍历,没有下一个节点;从 5 开始遍历,得到 3 和 4 节点。这一轮总共得到两个新节点:4 和 3 。 +第一层: -反复从新节点出发进行上述的遍历操作。 +- 0 -> {6,2,1,5}; -可以看到,每一轮遍历的节点都与根节点路径长度相同。设 di 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di<=dj。利用这个结论,可以求解最短路径 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径,如果继续遍历,之后再遍历到目的节点,所经过的路径就不是最短路径。 +第二层: + +- 6 -> {4} +- 2 -> {} +- 1 -> {} +- 5 -> {4,3} + +第三层: + +- 4 -> {} +- 3 -> {} + +可以看到,每一轮遍历的节点都与根节点路径长度相同。设 di 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 di<=dj。利用这个结论,可以求解最短路径等 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径,如果继续遍历,之后再遍历到目的节点,所经过的路径就不是最短路径。 在程序实现 BFS 时需要考虑以下问题: -- 队列:用来存储每一轮遍历的节点 -- 标记:对于遍历过得节点,应该将它标记,防止重复遍历; +- 队列:用来存储每一轮遍历的节点; +- 标记:对于遍历过的节点,应该将它标记,防止重复遍历。 **计算在网格中从原点到特定点的最短路径长度** ```html [[1,1,0,1], -[1,0,1,0], -[1,1,1,1], -[1,0,1,1]] + [1,0,1,0], + [1,1,1,1], + [1,0,1,1]] ``` +1 表示可以经过某个位置。 + ```java public int minPathLength(int[][] grids, int tr, int tc) { int[][] next = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; @@ -803,14 +819,14 @@ private class Position {

-广度优先搜索一层一层遍历,每一层遍历到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在遍历到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。 +广度优先搜索一层一层遍历,每一层得到到的所有新节点,要用队列先存储起来以备下一层遍历的时候再遍历;而深度优先搜索在得到到一个新节点时立马对新节点进行遍历:从节点 0 出发开始遍历,得到到新节点 6 时,立马对新节点 6 进行遍历,得到新节点 4;如此反复以这种方式遍历新节点,直到没有新节点了,此时返回。返回到根节点 0 的情况是,继续对根节点 0 进行遍历,得到新节点 2,然后继续以上步骤。 从一个节点出发,使用 DFS 对一个图进行遍历时,能够遍历到的节点都是从初始节点可达的,DFS 常用来求解这种 **可达性** 问题。 在程序实现 DFS 时需要考虑以下问题: -- 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。也可以使用递归栈。 -- 标记:和 BFS 一样同样需要对已经遍历过得节点进行标记。 +- 栈:用栈来保存当前节点信息,当遍历新节点返回时能够继续遍历当前节点。可以使用递归栈。 +- 标记:和 BFS 一样同样需要对已经遍历过的节点进行标记。 **查找最大的连通面积** @@ -818,13 +834,13 @@ private class Position { ```html [[0,0,1,0,0,0,0,1,0,0,0,0,0], -[0,0,0,0,0,0,0,1,1,1,0,0,0], -[0,1,1,0,1,0,0,0,0,0,0,0,0], -[0,1,0,0,1,1,0,0,1,0,1,0,0], -[0,1,0,0,1,1,0,0,1,1,1,0,0], -[0,0,0,0,0,0,0,0,0,0,1,0,0], -[0,0,0,0,0,0,0,1,1,1,0,0,0], -[0,0,0,0,0,0,0,1,1,0,0,0,0]] + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,1,1,0,1,0,0,0,0,0,0,0,0], + [0,1,0,0,1,1,0,0,1,0,1,0,0], + [0,1,0,0,1,1,0,0,1,1,1,0,0], + [0,0,0,0,0,0,0,0,0,0,1,0,0], + [0,0,0,0,0,0,0,1,1,1,0,0,0], + [0,0,0,0,0,0,0,1,1,0,0,0,0]] ``` ```java @@ -1083,74 +1099,11 @@ private void dfs(int r, int c, boolean[][] canReach) { } ``` -**N 皇后** - -[Leetcode : 51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/) - -

- -题目描述:在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,要求解所有的 n 皇后解。 - -一行一行地摆放,在确定一行中的那个皇后应该摆在哪一列时,需要用三个标记数组来确定某一列是否合法,这三个标记数组分别为:列标记数组、45 度对角线标记数组和 135 度对角线标记数组。 - -45 度对角线标记数组的维度为 2\*n - 1,通过下图可以明确 (r,c) 的位置所在的数组下标为 r + c。 - -

- -135 度对角线标记数组的维度也是 2\*n - 1,(r,c) 的位置所在的数组下标为 n - 1 - (r - c)。 - -

- -```java -private List> ret; -private char[][] nQueens; -private boolean[] colUsed; -private boolean[] diagonals45Used; -private boolean[] diagonals135Used; -private int n; - -public List> solveNQueens(int n) { - ret = new ArrayList<>(); - nQueens = new char[n][n]; - Arrays.fill(nQueens, '.'); - colUsed = new boolean[n]; - diagonals45Used = new boolean[2 * n - 1]; - diagonals135Used = new boolean[2 * n - 1]; - this.n = n; - backstracking(0); - return ret; -} - -private void backstracking(int row) { - if (row == n) { - List list = new ArrayList<>(); - for (char[] chars : nQueens) { - list.add(new String(chars)); - } - ret.add(list); - return; - } - - for (int col = 0; col < n; col++) { - int diagonals45Idx = row + col; - int diagonals135Idx = n - 1 - (row - col); - if (colUsed[col] || diagonals45Used[diagonals45Idx] || diagonals135Used[diagonals135Idx]) { - continue; - } - nQueens[row][col] = 'Q'; - colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = true; - backstracking(row + 1); - colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = false; - nQueens[row][col] = '.'; - } -} -``` - ### Backtracking 回溯是 DFS 的一种,它不是用在遍历图的节点上,而是用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串。 -在程序实现时,回溯需要注意对元素进行标记的问题。使用递归实现的回溯,在访问一个新元素进入新的递归调用,此时需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;但是在递归返回时,需要将该元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,而在不同的递归链是可以访问已经访问过但是不在当前递归链中的元素。 +在程序实现时,回溯需要注意对元素进行标记的问题。使用递归实现的回溯,在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;但是在递归返回时,需要将该元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。 **数字键盘组合** @@ -1327,7 +1280,7 @@ private void backtracking(List permuteList, boolean[] visited, int[] nu [[1,1,2], [1,2,1], [2,1,1]] ``` -题目描述:数组元素可能含有相同的元素,进行排列时就有可能出先重复的排列,要求重复的排列只返回一个。 +题目描述:数组元素可能含有相同的元素,进行排列时就有可能出现 重复的排列,要求重复的排列只返回一个。 在实现上,和 Permutations 不同的是要先排序,然后在添加一个元素时,判断这个元素是否等于前一个元素,如果等于,并且前一个元素还未访问,那么就跳过这个元素。 @@ -1389,8 +1342,7 @@ private void backtracking(int start, int n, int k, List combineList, Li return; } - for(int i = start; i <= n - k + 1; i++){ // 剪枝 - + for(int i = start; i <= n - k + 1; i++) { // 剪枝 combineList.add(i); // 把 i 标记为已访问 backtracking(i + 1, n, k - 1, combineList, ret); combineList.remove(combineList.size() - 1); // 把 i 标记为未访问 @@ -1502,7 +1454,7 @@ private void backtracking(int startIdx, int size, int[] nums) { for (int i = startIdx; i < nums.length; i++) { subsetList.add(nums[i]); - backtracking(i + 1, size, nums); // startIdx 设为下一个元素,使 subset 中的元素都递增排序 + backtracking(i + 1, size, nums); subsetList.remove(subsetList.size() - 1); } } @@ -1559,10 +1511,20 @@ private void backtracking(int startIdx, int size, int[] nums) { } ``` -**分割字符串使得每部分都是回文数** +**分割字符串使得每个部分都是回文数** [Leetcode : 131. Palindrome Partitioning (Medium)](https://leetcode.com/problems/palindrome-partitioning/description/) +```html +For example, given s = "aab", +Return + +[ + ["aa","b"], + ["a","a","b"] +] +``` + ```java private List> ret; @@ -1650,6 +1612,69 @@ private int cubeNum(int i, int j) { } ``` +**N 皇后** + +[Leetcode : 51. N-Queens (Hard)](https://leetcode.com/problems/n-queens/description/) + +

+ +题目描述:在 n\*n 的矩阵中摆放 n 个皇后,并且每个皇后不能在同一行,同一列,同一对角线上,要求解所有的 n 皇后解。 + +一行一行地摆放,在确定一行中的那个皇后应该摆在哪一列时,需要用三个标记数组来确定某一列是否合法,这三个标记数组分别为:列标记数组、45 度对角线标记数组和 135 度对角线标记数组。 + +45 度对角线标记数组的维度为 2\*n - 1,通过下图可以明确 (r,c) 的位置所在的数组下标为 r + c。 + +

+ +135 度对角线标记数组的维度也是 2\*n - 1,(r,c) 的位置所在的数组下标为 n - 1 - (r - c)。 + +

+ +```java +private List> ret; +private char[][] nQueens; +private boolean[] colUsed; +private boolean[] diagonals45Used; +private boolean[] diagonals135Used; +private int n; + +public List> solveNQueens(int n) { + ret = new ArrayList<>(); + nQueens = new char[n][n]; + Arrays.fill(nQueens, '.'); + colUsed = new boolean[n]; + diagonals45Used = new boolean[2 * n - 1]; + diagonals135Used = new boolean[2 * n - 1]; + this.n = n; + backstracking(0); + return ret; +} + +private void backstracking(int row) { + if (row == n) { + List list = new ArrayList<>(); + for (char[] chars : nQueens) { + list.add(new String(chars)); + } + ret.add(list); + return; + } + + for (int col = 0; col < n; col++) { + int diagonals45Idx = row + col; + int diagonals135Idx = n - 1 - (row - col); + if (colUsed[col] || diagonals45Used[diagonals45Idx] || diagonals135Used[diagonals135Idx]) { + continue; + } + nQueens[row][col] = 'Q'; + colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = true; + backstracking(row + 1); + colUsed[col] = diagonals45Used[diagonals45Idx] = diagonals135Used[diagonals135Idx] = false; + nQueens[row][col] = '.'; + } +} +``` + ## 分治 **给表达式加括号** @@ -3567,9 +3592,9 @@ Input: nums = [1,2,2,4] Output: [2,3] ``` -最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(nlogn).本题可以以 O(n) 的时间复杂度、O(1) 空间复杂度来求解。 +最直接的方法是先对数组进行排序,这种方法时间复杂度为 O(nlogn)。本题可以以 O(n) 的时间复杂度、O(1) 空间复杂度来求解。 -主要思想是让通过交换数组元素,使得数组上的元素在正确的位置上 +主要思想是让通过交换数组元素,使得数组上的元素在正确的位置上。 遍历数组,如果第 i 位上的元素不是 i + 1 ,那么就交换第 i 位 和 nums[i] - 1 位上的元素,使得 num[i] - 1 的元素为 nums[i] ,也就是该位的元素是正确的。交换操作需要循环进行,因为一次交换没办法使得第 i 位上的元素是正确的。但是要交换的两个元素可能就是重复元素,那么循环就可能永远进行下去,终止循环的方法是加上 nums[i] != nums[nums[i] - 1 条件。 @@ -4235,9 +4260,10 @@ private TreeNode toBST(int[] nums, int sIdx, int eIdx){ **两节点的最长路径** +[Leetcode : 543. Diameter of Binary Tree (Easy)](https://leetcode.com/problems/diameter-of-binary-tree/description/) + ```html Input: - 1 / \ 2 3 @@ -4247,8 +4273,6 @@ Input: Return 3, which is the length of the path [4,2,1,3] or [5,2,1,3]. ``` -[Leetcode : 543. Diameter of Binary Tree (Easy)](https://leetcode.com/problems/diameter-of-binary-tree/description/) - ```java private int max = 0; @@ -4931,7 +4955,7 @@ class MapSum { **1. 基本原理** -0s 表示 一串 0 ,1s 表示一串 1。 +0s 表示一串 0 ,1s 表示一串 1。 ``` x ^ 0s = x x & 0s = 0 x | 0s = x @@ -4941,7 +4965,7 @@ x ^ x = 0 x & x = x x | x = x ① 利用 x ^ 1s = \~x 的特点,可以将位级表示翻转;利用 x ^ x = 0 的特点,可以将三个数中重复的两个数去除,只留下另一个数; ② 利用 x & 0s = 0 和 x & 1s = x 的特点,可以实现掩码操作。一个数 num 与 mask :00111100 进行位与操作,只保留 num 中与 mask 的 1 部分相对应的位; -③ 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设置操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1 。 +③ 利用 x | 0s = x 和 x | 1s = 1s 的特点,可以实现设值操作。一个数 num 与 mask:00111100 进行位或操作,将 num 中与 mask 的 1 部分相对应的位都设置为 1 。 \>\> n 为算术右移,相当于除以 2n; \>\>\> n 为无符号右移,左边会补上 0。 @@ -4949,7 +4973,7 @@ x ^ x = 0 x & x = x x | x = x n&(n-1) 该位运算是去除 n 的位级表示中最低的那一位。例如对于二进制表示 10110 **100** ,减去 1 得到 10110**011**,这两个数相与得到 10110**000**。 -n-n&(\~n+1) 概运算是去除 n 的位级表示中最高的那一位。 +n-n&(\~n+1) 运算是去除 n 的位级表示中最高的那一位。 n&(-n) 该运算得到 n 的位级表示中最低的那一位。-n 得到 n 的反码加 1,对于二进制表示 10110 **100** ,-n 得到 01001**100**,相与得到 00000**100** @@ -5016,9 +5040,9 @@ num & (~((1 << (i+1)) - 1)); **4. Java 中的位操作** ```html -static int Integer.bitCount() // 统计 1 的数量 -static int Integer.highestOneBit() // 获得最高位 -static String toBinaryString(int i) // 转换位二进制表示的字符串 +static int Integer.bitCount(); // 统计 1 的数量 +static int Integer.highestOneBit(); // 获得最高位 +static String toBinaryString(int i); // 转换为二进制表示的字符串 ``` **统计两个数的二进制表示有多少位不同** @@ -5073,13 +5097,13 @@ b = a ^ b; a = a ^ b; ``` -将 c = a ^ b,那么 b ^ c = b ^ b ^ a = a,a ^ c = a ^ a ^ b = b。 +令 c = a ^ b,那么 b ^ c = b ^ b ^ a = a,a ^ c = a ^ a ^ b = b。 **判断一个数是不是 4 的 n 次方** [Leetcode : 342. Power of Four (Easy)](https://leetcode.com/problems/power-of-four/) -该数二进制表示有且只有一个奇数位为 1 ,其余的都为 0 ,例如 16 : 10000。可以每次把 1 向左移动 2 位,就能构造出这种数字,然后比较构造出来的数与要判断的数是否相同。 +该数二进制表示有且只有一个奇数位为 1 ,其余的都为 0 ,例如 16 :10000。可以每次把 1 向左移动 2 位,就能构造出这种数字,然后比较构造出来的数与要判断的数是否相同。 ```java public boolean isPowerOfFour(int num) { @@ -5092,14 +5116,6 @@ public boolean isPowerOfFour(int num) { } ``` -也可以用 Java 的 Integer.toString() 方法将该数转换为 4 进制形式的字符串,然后判断字符串是否以 1 开头。 - -```java -public boolean isPowerOfFour(int num) { - return Integer.toString(num, 4).matches("10*"); -} -``` - **判断一个数是不是 2 的 n 次方** [Leetcode : 231. Power of Two (Easy)](https://leetcode.com/problems/power-of-two/description/) diff --git a/notes/分布式问题分析.md b/notes/分布式问题分析.md index 228d3fb6..81d7f9e0 100644 --- a/notes/分布式问题分析.md +++ b/notes/分布式问题分析.md @@ -11,11 +11,10 @@ * [使用场景](#使用场景) * [实现方式](#实现方式) * [五、分布式 Session](#五分布式-session) - * [1. 粘性 Session](#1-粘性-session) - * [2. 服务器 Session 复制](#2-服务器-session-复制) - * [3. Session 共享机制](#3-session-共享机制) - * [4. Session 持久化到数据库](#4-session-持久化到数据库) - * [5. Terracotta 实现 Session 复制](#5-terracotta-实现-session-复制) + * [1. Sticky Sessions](#1-sticky-sessions) + * [2. Session Replication](#2-session-replication) + * [3. Persistent DataStore](#3-persistent-datastore) + * [4. In-Memory DataStore](#4-in-memory-datastore) * [六、分库与分表带来的分布式困境与应对之策](#六分库与分表带来的分布式困境与应对之策) * [事务问题](#事务问题) * [查询问题](#查询问题) @@ -28,7 +27,7 @@ 分布式主要是为了提供可扩展性以及高可用性,业务中使用分布式的场景主要有分布式存储以及分布式计算。 -分布式存储中可以将数据分片到多个节点上,不仅可以提高性能(可扩展性),同时也可以使用多个节点对同一份数据进行备份。 +分布式存储中可以将数据分片到多个节点上,不仅可以提高性能(可扩展性),同时也可以使用多个节点对同一份数据进行备份(高可用性)。 至于分布式计算,就是将一个大的计算任务分解成小任务分配到多台节点上去执行,再汇总每个小任务的执行结果得到最终结果。MapReduce 是分布式计算的最好例子。 @@ -43,7 +42,7 @@ ## 应用场景 -- 下单:减少库存、更新订单状态。库存和订单不在不同一个数据库,因此涉及分布式事务。 +- 下单:减少库存、更新订单状态。库存和订单不在同一个数据库,因此涉及分布式事务。 - 支付:买家账户扣款、卖家账户入账。买家和卖家账户信息不在同一个数据库,因此涉及分布式事务。 ## 解决方案 @@ -128,37 +127,49 @@ ## 实现 -### 1. DNS 解析 - -使用 DNS 作为负载均衡器,根据负载情况返回不同服务器的 IP 地址。大型网站基本使用了这种方式最为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。 - -

- -### 2. 修改 MAC 地址 - -使用 LVS(Linux Virtual Server)这种链路层负载均衡器,根据负载情况修改请求的 MAC 地址。 - -

- -### 3. 修改 IP 地址 - -在网络层修改请求的目的 IP 地址。 - -

- -### 4. HTTP 重定向 +### 1. HTTP 重定向 HTTP 重定向负载均衡服务器收到 HTTP 请求之后会返回服务器的地址,并将该地址写入 HTTP 重定向响应中返回给浏览器,浏览器收到后需要再次发送请求。 -

+缺点: -### 5. 反向代理 +- 用户访问的延迟会增加; +- 如果负载均衡器宕机,就无法访问该站点。 -正向代理:发生在客户端,是由用户主动发起的。比如翻墙,客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端。 +

-反向代理:发生在服务器端,用户不知道代理的存在。 +### 2. DNS 重定向 -

+使用 DNS 作为负载均衡器,根据负载情况返回不同服务器的 IP 地址。大型网站基本使用了这种方式做为第一级负载均衡手段,然后在内部使用其它方式做第二级负载均衡。 + +缺点: + +- DNS 查找表可能会被客户端缓存起来,那么之后的所有请求都会被重定向到同一个服务器。 + +

+ +### 3. 修改 MAC 地址 + +使用 LVS(Linux Virtual Server)这种链路层负载均衡器,根据负载情况修改请求的 MAC 地址。 + +

+ +### 4. 修改 IP 地址 + +在网络层修改请求的目的 IP 地址。 + +

+ +### 5. 代理自动配置 + +正向代理与反向代理的区别: + +- 正向代理:发生在客户端,是由用户主动发起的。比如翻墙,客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端。 +- 反向代理:发生在服务器端,用户不知道代理的存在。 + +PAC 服务器是用来判断一个请求是否要经过代理。 + +

# 四、分布式锁 @@ -194,7 +205,7 @@ EXPIRE 可以为一个键值对设置一个过期时间,从而避免了死锁 **(二)RedLock 算法** -ReadLock 算法使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用。 +RedLock 算法使用了多个 Redis 实例来实现分布式锁,这是为了保证在发生单点故障时还可用。 1. 尝试从 N 个相互独立 Redis 实例获取锁,如果一个实例不可用,应该尽快尝试下一个。 2. 计算获取锁消耗的时间,只有当这个时间小于锁的过期时间,并且从大多数(N/2+1)实例上获取了锁,那么就认为锁获取成功了。 @@ -237,99 +248,37 @@ Zookeeper 提供了一种树形结构级的命名空间,/app1/p_1 节点表示 # 五、分布式 Session -如果不做任何处理的话,用户将出现频繁登录的现象,比如集群中存在 A、B 两台服务器,用户在第一次访问网站时,Nginx 通过其负载均衡机制将用户请求转发到 A 服务器,这时 A 服务器就会给用户创建一个 Session。当用户第二次发送请求时,Nginx 将其负载均衡到 B 服务器,而这时候 B 服务器并不存在 Session,所以就会将用户踢到登录页面。这将大大降低用户体验度,导致用户的流失,这种情况是项目绝不应该出现的。 +在分布式场景下,一个用户的 Session 如果只存储在一个服务器上,那么当负载均衡器把用户的下一个请求转发到另一个服务器上,该服务器没有保存用户的 Session,就可能导致用户需要重新进行登录等操作。 -## 1. 粘性 Session +

-### 原理 +## 1. Sticky Sessions -粘性 Session 是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 Session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 Session 机制。 +需要配置负载均衡器,使得一个用户的所有请求都路由到一个服务器节点上,这样就可以把用户的 Session 存放在该服务器节点中。 -### 优点 +缺点:当服务器节点宕机时,将丢失该服务器节点上的所有 Session。 -简单,不需要对 Session 做任何处理。 +

-### 缺点 +## 2. Session Replication -缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 Session 信息都将失效。 +在服务器节点之间进行 Session 同步操作,这样的话用户可以访问任何一个服务器节点。 -### 适用场景 +缺点:需要更好的服务器硬件条件;需要对服务器进行配置。 -- 发生故障对客户产生的影响较小; -- 服务器发生故障是低概率事件。 +

-## 2. 服务器 Session 复制 +## 3. Persistent DataStore -### 原理 +将 Session 信息持久化到一个数据库中。 -任何一个服务器上的 Session 发生改变,该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 Session,以此来保证 Session 同步。 +缺点:有可能需要去实现存取 Session 的代码。 -### 优点 +

-可容错,各个服务器间 Session 能够实时响应。 +## 4. In-Memory DataStore -### 缺点 - -会对网络负荷造成一定压力,如果 Session 量大的话可能会造成网络堵塞,拖慢服务器性能。 - -### 实现方式 - -1. 设置 Tomcat 的 server.xml 开启 tomcat 集群功能。 -2. 在应用里增加信息:通知应用当前处于集群环境中,支持分布式,即在 web.xml 中添加<distributable/> 选项。 - -## 3. Session 共享机制 - -使用分布式缓存方案比如 Memcached、Redis,但是要求 Memcached 或 Redis 必须是集群。 - -使用 Session 共享也分两种机制,两种情况如下: - -### 3.1 粘性 Session 共享机制 - -和粘性 Session 一样,一个用户的 Session 会绑定到一个 Tomcat 上。Memcached 只是起到备份作用。 - -

- -### 3.2 非粘性 Session 共享机制 - -#### 原理 - -Tomcat 本身不存储 Session,而是存入 Memcached 中。Memcached 集群构建主从复制架构。 - -

- -#### 优点 - -可容错,Session 实时响应。 - -#### 实现方式 - -用开源的 msm 插件解决 Tomcat 之间的 Session 共享:Memcached_Session_Manager(MSM) - -## 4. Session 持久化到数据库 - -### 原理 - -拿出一个数据库,专门用来存储 Session 信息。保证 Session 的持久化。 - -### 优点 - -服务器出现问题,Session 不会丢失 - -### 缺点 - -如果网站的访问量很大,把 Session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。 - -## 5. Terracotta 实现 Session 复制 - -### 原理 - -Terracotta 的基本原理是对于集群间共享的数据,当在一个节点发生变化的时候,Terracotta 只把变化的部分发送给 Terracotta 服务器,然后由服务器把它转发给真正需要这个数据的节点。它是服务器 Session 复制的优化。 - -

- -### 优点 - -这样对网络的压力就非常小,各个节点也不必浪费 CPU 时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在 Session 同步上,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果。 +可以使用 Redis 和 Memcached 这种内存型数据库对 Session 进行存储,可以大大提高 Session 的读写效率。内存型数据库同样可以持久化数据到磁盘中来保证数据的安全性。 # 六、分库与分表带来的分布式困境与应对之策 @@ -353,6 +302,9 @@ Terracotta 的基本原理是对于集群间共享的数据,当在一个节点 - [Comparing Load Balancing Algorithms](http://www.jscape.com/blog/load-balancing-algorithms) - [负载均衡算法及手段](https://segmentfault.com/a/1190000004492447) +- [Redirection and Load Balancing](http://slideplayer.com/slide/6599069/#) +- [Session Management using Spring Session with JDBC DataStore](https://sivalabs.in/2018/02/session-management-using-spring-session-jdbc-datastore/) +- [Apache Wicket User Guide - Reference Documentation](# Apache Wicket User Guide - Reference Documentation) - [集群/分布式环境下 5 种 Session 处理策略](http://blog.csdn.net/u010028869/article/details/50773174?ref=myread) - [浅谈分布式锁](http://www.linkedkeeper.com/detail/blog.action?bid=1023) - [深入理解分布式事务](https://juejin.im/entry/577c6f220a2b5800573492be) diff --git a/notes/数据库系统原理.md b/notes/数据库系统原理.md index cd13daa5..d7246a79 100644 --- a/notes/数据库系统原理.md +++ b/notes/数据库系统原理.md @@ -125,8 +125,8 @@ MySQL 中提供了两种封锁粒度:行级锁以及表级锁。 | - | X | S | | :--: | :--: | :--: | -|X|Yes|No| -|S|No|No| +|X|NO|No| +|S|No|Yes| ### 2. 意向锁 @@ -258,9 +258,7 @@ lock-x(A)...unlock(A)...lock-s(B)...unlock(B)...lock-s(c)...unlock(C)... # 五、多版本并发控制 -(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,它的基本思想是通过保存每个数据行的多个版本,一个事务对数据行做修改时,其它事务可以读取之前的一个版本,并且都是读取相同的版本,从而保证多个事务对同一个数据行读取的结果是一致的。 - -用于实现提交读和可重复读这两种隔离级别。而对于未提交读隔离级别,它总是读取最新的数据行,无需使用 MVCC;可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。 +(Multi-Version Concurrency Control, MVCC)是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别。而未提交读隔离级别总是读取最新的数据行,无需使用 MVCC;可串行化隔离级别需要对所有读取的行都加锁,单纯使用 MVCC 无法实现。 ## 版本号 @@ -280,9 +278,11 @@ InnoDB 的 MVCC 使用到的快照存储在 Undo 日志中,该日志通过回 ## 实现过程 +以下过程针对可重复读隔离级别。 + ### 1. SELECT -该操作必须保证多个事务读取到同一个数据行的快照。但是也有例外,如果有一个事务正在修改该数据行,那么它可以读取事务本身所做的修改,而不用和其它事务的读取结果一致。 +该操作必须保证多个事务读取到同一个数据行的快照,这个快照是最近的一个有效快照。但是也有例外,如果有一个事务正在修改该数据行,那么它可以读取事务本身所做的修改,而不用和其它事务的读取结果一致。 当开始新一个事务时,该事务的版本号肯定会大于所有数据行快照的创建版本号,理解这一点很关键。 diff --git a/notes/算法.md b/notes/算法.md index df40054a..9377a9ab 100644 --- a/notes/算法.md +++ b/notes/算法.md @@ -52,13 +52,13 @@ 使用 \~f(N) 来表示所有随着 N 的增大除以 f(N) 的结果趋近于 1 的函数,例如 N3/6-N2/2+N/3 \~ N3/6。 -

+

### 2. 增长数量级 增长数量级将算法与它的实现隔离开来,一个算法的增长数量级为 N3 与它是否用 Java 实现,是否运行于特定计算机上无关。 -

+

### 3. 内循环 @@ -157,7 +157,7 @@ public class ThreeSumFast { first-in-last-out(FILO) -

+

**1. 数组实现**
@@ -269,7 +269,7 @@ public class Stack { first-in-first-out(FIFO) -

+

下面是队列的链表实现,需要维护 first 和 last 节点指针,分别指向队首和队尾。 @@ -324,11 +324,11 @@ public class Queue { 用于解决动态连通性问题,能动态连接两个点,并且判断两个点是否连通。 -

+

**API**
-

+

**基本数据结构**
@@ -375,7 +375,7 @@ public class UF { 在 union 时只将节点的 id 值指向另一个节点 id 值,不直接用 id 来存储所属的连通分量。这样就构成一个倒置的树形结构,应该注意的是根节点需要指向自己。查找一个节点所属的连通分量时,要一直向上查找直到根节点,并使用根节点的 id 值作为本连通分量的 id 值。 -

+

```java public int find(int p) { @@ -448,7 +448,7 @@ public class WeightedQuickUnionUF { ## 各种 union-find 算法的比较 -

+

# 四、排序 @@ -476,7 +476,7 @@ private void exch(Comparable[] a, int i, int j){ 找到数组中的最小元素,将它与数组的第一个元素交换位置。再从剩下的元素中找到最小的元素,将它与数组的第二个元素交换位置。不断进行这样的操作,直到将整个数组排序。 -

+

```java public class Selection { @@ -499,7 +499,7 @@ public class Selection { 插入排序从左到右进行,每次都将当前元素插入到左部已经排序的数组中,使得插入之后左部数组依然有序。 -

+

```java public class Insertion { @@ -530,9 +530,9 @@ public class Insertion { 希尔排序使用插入排序对间隔 h 的序列进行排序,如果 h 很大,那么元素就能很快的移到很远的地方。通过不断减小 h,最后令 h=1,就可以使得整个数组是有序的。 -

+

-

+

```java public class Shell { @@ -560,7 +560,7 @@ public class Shell { 归并排序的思想是将数组分成两部分,分别进行排序,然后归并起来。 -

+


@@ -591,7 +591,7 @@ public class MergeSort { ### 2. 自顶向下归并排序 -

+

```java public static void sort(Comparable[] a) { @@ -616,7 +616,7 @@ private static void sort(Comparable[] a, int lo, int hi) { 先归并那些微型数组,然后成对归并得到的子数组。 -

+

```java public static void busort(Comparable[] a) { @@ -729,7 +729,7 @@ public class Quick3Way { 堆可以用数组来表示,因为堆是一种完全二叉树,而完全二叉树很容易就存储在数组中。位置 k 的节点的父节点位置为 k/2,而它的两个子节点的位置分别为 2k 和 2k+1。这里我们不使用数组索引为 0 的位置,是为了更清晰地理解节点的关系。 -

+

```java public class MaxPQ { @@ -764,6 +764,8 @@ public class MaxPQ { 在堆中,当一个节点比父节点大,那么需要交换这个两个节点。交换后还可能比它新的父节点大,因此需要不断地进行比较和交换操作。把这种操作称为上浮。 +

+ ```java private void swim(int k) { while (k > 1 && less(k / 2, k)) { @@ -775,6 +777,8 @@ private void swim(int k) { 类似地,当一个节点比子节点来得小,也需要不断的向下比较和交换操作,把这种操作称为下沉。一个节点有两个子节点,应当与两个子节点中最大那么节点进行交换。 +

+ ```java private void sink(int k) { while (2 * k <= N) { @@ -820,7 +824,7 @@ public Key delMax() { 无序数组建立堆最直接的方法是从左到右遍历数组,然后进行上浮操作。一个更高效的方法是从右至左进行下沉操作,如果一个节点的两个节点都已经是堆有序,那么进行下沉操作可以使得这个节点为根节点的堆有序。叶子节点不需要进行下沉操作,因此可以忽略叶子节点的元素,因此只需要遍历一半的元素即可。 -

+

```java public static void sort(Comparable[] a){ @@ -849,9 +853,9 @@ public static void sort(Comparable[] a){ ### 1. 排序算法的比较 -

+

-快速排序时最快的通用排序算法,它的内循环的指令很少,而且它还能利用缓存,因为它总是顺序地访问数据。它的运行时间增长数量级为 \~cNlogN,这里的 c 比其他线性对数级别的排序算法都要小。使用三向切分之后,实际应用中可能出现的某些分布的输入能够达到线性级别,而其它排序算法仍然需要线性对数时间。 +快速排序时最快的通用排序算法,它的内循环的指令很少,而且它还能利用缓存,因为它总是顺序地访问数据。它的运行时间近似为 \~cNlogN,这里的 c 比其他线性对数级别的排序算法都要小。使用三向切分之后,实际应用中可能出现的某些分布的输入能够达到线性级别,而其它排序算法仍然需要线性对数时间。 ### 2. Java 的排序算法实现 @@ -886,11 +890,11 @@ public static Comparable select(Comparable[] a, int k) { ### 1. 无序符号表 -

+

### 2. 有序符号表 -

+

有序指的是支持 min() max() 等根据键的大小关系来实现的操作。 @@ -969,11 +973,11 @@ public class BinarySearchST, Value> { **二叉查找树** (BST)是一颗二叉树,并且每个节点的值都大于其左子树中的所有节点的值而小于右子树的所有节点的值。 -

+

BST 有一个重要性质,就是它的前序遍历结果递增排序。 -

+

基本数据结构: diff --git a/notes/计算机网络.md b/notes/计算机网络.md index d99e12b8..20b9e5f8 100644 --- a/notes/计算机网络.md +++ b/notes/计算机网络.md @@ -6,22 +6,23 @@ * [主机之间的通信方式](#主机之间的通信方式) * [电路交换与分组交换](#电路交换与分组交换) * [时延](#时延) - * [计算机网络体系结构 *](#计算机网络体系结构-) + * [计算机网络体系结构*](#计算机网络体系结构) * [二、物理层](#二物理层) * [通信方式](#通信方式) * [带通调制](#带通调制) * [信道复用技术](#信道复用技术) * [三、数据链路层](#三数据链路层) + * [信道分类](#信道分类) * [三个基本问题](#三个基本问题) - * [点对点信道 - PPP 协议](#点对点信道---ppp-协议) - * [局域网的拓扑](#局域网的拓扑) - * [广播信道- CSMA/CD 协议 *](#广播信道--csmacd-协议-) - * [扩展局域网 *](#扩展局域网-) - * [MAC 层 *](#mac-层-) -* [四、网络层 *](#四网络层-) - * [网际协议 IP 概述](#网际协议-ip-概述) + * [局域网](#局域网) + * [PPP 协议](#ppp-协议) + * [CSMA/CD 协议*](#csmacd-协议) + * [扩展局域网*](#扩展局域网) + * [MAC 层*](#mac-层) +* [四、网络层*](#四网络层) + * [概述](#概述) * [IP 数据报格式](#ip-数据报格式) - * [IP 地址编址](#ip-地址编址) + * [IP 地址编址方式](#ip-地址编址方式) * [IP 地址和 MAC 地址](#ip-地址和-mac-地址) * [地址解析协议 ARP](#地址解析协议-arp) * [路由器的结构](#路由器的结构) @@ -32,7 +33,7 @@ * [IP 多播](#ip-多播) * [虚拟专用网 VPN](#虚拟专用网-vpn) * [网络地址转换 NAT](#网络地址转换-nat) -* [五、运输层 *](#五运输层-) +* [五、运输层*](#五运输层) * [UDP 和 TCP 的特点](#udp-和-tcp-的特点) * [UDP 首部格式](#udp-首部格式) * [TCP 首部格式](#tcp-首部格式) @@ -42,7 +43,7 @@ * [TCP 可靠传输](#tcp-可靠传输) * [TCP 流量控制](#tcp-流量控制) * [TCP 拥塞控制](#tcp-拥塞控制) -* [六、应用层 *](#六应用层-) +* [六、应用层*](#六应用层) * [域名系统 DNS](#域名系统-dns) * [文件传输协议 FTP](#文件传输协议-ftp) * [远程终端协议 TELNET](#远程终端协议-telnet) @@ -62,7 +63,7 @@ 网络把主机连接起来,而互联网是把多种不同的网络连接起来,因此互联网是网络的网络。 -

+

## ISP @@ -72,7 +73,7 @@ 互联网交换点 IXP 允许两个 ISP 直接相连而不用经过第三个 ISP。 -

+

## 互联网的组成 @@ -80,7 +81,7 @@ 2. 核心部分:由大量的网络和连接这些网络的路由器组成,为边缘部分的主机提供服务。 -

+

## 主机之间的通信方式 @@ -90,7 +91,7 @@ ## 电路交换与分组交换 -

+

### 1. 电路交换 @@ -104,9 +105,9 @@ 分组交换也使用了存储转发,但是转发的是分组而不是报文。把整块数据称为一个报文,由于一个报文可能很长,需要先进行切分,来满足分组能处理的大小。在每个切分的数据前面加上首部之后就成为了分组,首部包含了目的地址和源地址等控制信息。 -

+

-存储转发允许在一条传输线路上传送多个主机的分组,因此两个用户之间的通信不需要占用端到端的线路资源。 +存储转发允许在一条传输线路上传送多个主机的分组,也就是说两个用户之间的通信不需要占用端到端的线路资源。 相比于报文交换,由于分组比报文更小,因此分组交换的存储转发速度更加快速。 @@ -114,7 +115,7 @@ 总时延 = 发送时延 + 传播时延 + 处理时延 + 排队时延 -

+

### 1. 发送时延 @@ -134,15 +135,15 @@ ### 3. 处理时延 -主机或路由器收到分组时进行处理所需要的时间,例如分析首部,从分组中提取数据部分等。 +主机或路由器收到分组时进行处理所需要的时间,例如分析首部、从分组中提取数据部、进行差错检验或查找适当的路由等。 ### 4. 排队时延 分组在路由器的输入队列和输出队列中排队等待的时间,取决于网络当前的通信量。 -## 计算机网络体系结构 * +## 计算机网络体系结构* -

+

### 1. 七层协议 @@ -157,9 +158,9 @@ 2. 运输层:提供的是进程间的通用数据传输服务。由于应用层协议很多,定义通用的运输层协议就可以支持不断增多的应用层协议。运输层包括两种协议:传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;用户数据报协议 UDP,提供无连接、尽最大努力的数据传输服务,数据单位为用户数据报。TCP 主要提供完整性服务,UDP 主要提供及时性服务。 -3. 网络层:为主机之间提供数据传输服务,而像运输层协议那样是为主机中的进程提供服务。网络层把运输层传递下来的报文段或者用户数据报封装成分组。 +3. 网络层:为主机之间提供数据传输服务,而运输层协议是为主机中的进程提供服务。网络层把运输层传递下来的报文段或者用户数据报封装成分组。 -4. 数据链路层:网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为相邻结点之间提供服务。数据链路层把网络层传来的分组封装成帧。 +4. 数据链路层:网络层针对的还是主机之间的数据传输服务,而主机之间可以有很多链路,链路层协议就是为同一链路的结点提供服务。数据链路层把网络层传来的分组封装成帧。 5. 物理层:考虑的是怎样在传输媒体上传输数据比特流,而不是指具体的传输媒体。物理层的作用是尽可能屏蔽传输媒体和通信手段的差异,使数据链路层感觉不到这些差异。 @@ -169,7 +170,7 @@ 路由器只有下面三层协议,因为路由器位于网络核心中,不需要为进程或者应用程序提供服务,因此也就不需要运输层和应用层。 -

+

### 4. TCP/IP 体系结构 @@ -177,11 +178,11 @@ 现在的 TCP/IP 体系结构不严格遵循 OSI 分层概念,应用层可能会直接使用 IP 层或者网络接口层。 -

+

TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中占用举足轻重的地位。 -

+

# 二、物理层 @@ -195,7 +196,7 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中 模拟信号是连续的信号,数字信号是离散的信号。带通调制把数字信号转换为模拟信号。 -

+

## 信道复用技术 @@ -203,21 +204,21 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中 频分复用的所有用户在相同的时间占用不同的频率带宽资源;时分复用的所有用户在不同的时间占用相同的频率带宽资源。 -使用这两种方式进行通信,在通信的过程中用户会一直占用一部分信道资源。但是由于计算机数据的突发性质,没必要一直占用信道资源而不让出给其它用户使用,因此这两种方式对信道的利用率都不高。 +使用这两种方式进行通信,在通信的过程中用户会一直占用一部分信道资源。但是由于计算机数据的突发性质,通信过程没必要一直占用信道资源而不让出给其它用户使用,因此这两种方式对信道的利用率都不高。 -

+

### 2. 统计时分复用 是对时分复用的一种改进,不固定每个用户在时分复用帧中的位置,只要有数据就集中起来组成统计时分复用帧然后发送。 -

+

### 3. 波分复用 光的频分复用。由于光的频率很高,因此习惯上用波长而不是频率来表示所使用的光载波。 -

+

### 4. 码分复用 @@ -239,17 +240,22 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中 码分复用需要发送的数据量为原先的 m 倍。 -

+

# 三、数据链路层 +## 信道分类 + +1. 点对点信道:一对一通信方式; +2. 广播信道:一对多通信方式。 + ## 三个基本问题 ### 1. 封装成帧 将网络层传下来的分组添加首部和尾部,用于标记帧的开始和结束。 -

+

### 2. 透明传输 @@ -257,50 +263,52 @@ TCP/IP 协议族是一种沙漏形状,中间小两边大,IP 协议在其中 帧使用首部和尾部进行定界,如果帧的数据部分含有和首部尾部相同的内容,那么帧的开始和结束位置就会被错误的判定。需要在数据部分出现首部尾部相同的内容前面插入转义字符,如果出现转移字符,那么就在转义字符前面再加个转义字符,在接收端进行处理之后可以还原出原始数据。这个过程透明传输的内容是转义字符,用户察觉不到转义字符的存在。 -

+

### 3. 差错检测 目前数据链路层广泛使用了循环冗余检验(CRC)来检查比特差错。 -## 点对点信道 - PPP 协议 +## 局域网 -互联网用户通常需要连接到某个 ISP 之后才能接入到互联网,PPP 协议就是用户计算机和 ISP 进行通信时所使用的数据链路层协议。 +局域网是典型的一种广播信道,主要特点是网络为一个单位所拥有,且地理范围和站点数目均有限。 -

+可以按照网络拓扑对局域网进行分类: -在 PPP 的帧中 +

+ +## PPP 协议 + +用于点对点信道中。互联网用户通常需要连接到某个 ISP 之后才能接入到互联网,PPP 协议是用户计算机和 ISP 进行通信时所使用的数据链路层协议。 + +

+ +在 PPP 的帧中: - F 字段为帧的定界符 - A 和 C 字段暂时没有意义 - FCS 字段是使用 CRC 的检验序列 - 信息部分的长度不超过 1500 -

+

-## 局域网的拓扑 +## CSMA/CD 协议* -

- -## 广播信道- CSMA/CD 协议 * - -在广播信道上,同一时间只能允许一台计算机发送数据。 +用于广播信道中。在广播信道上,同一时间只能允许一台计算机发送数据。 CSMA/CD 表示载波监听多点接入 / 碰撞检测。 - **多点接入** :说明这是总线型网络,许多计算机以多点的方式连接到总线上。 +- **载波监听** :每个站都必须不停地监听信道。在发送前,如果监听到信道正在使用,就必须等待。 +- **碰撞检测** :在发送中,如果监听到信道已有其它站正在发送数据,就表示发生了碰撞。虽然每一个站在发送数据之前都已经监听到信道为空闲,但是由于电磁波的传播时延的存在,还是有可能会发生碰撞。 -- **载波监听** :每个站都必须不停地监听信道。在发送前,如果检听信道正在使用,就必须等待。 - -- **碰撞检测** :在发送中,如果监听 到信道已有其它站正在发送数据,就表示发生了碰撞。虽然每一个站在发送数据之前都已经监听到信道为空闲,但是由于电磁波的传播时延的存在,还是有可能会发生碰撞。 - -

+

记端到端的传播时延为 τ,最先发送的站点最多经过 2τ 就可以知道是否发生了碰撞,称 2τ 为 **争用期** 。只有经过争用期之后还没有检测到碰撞,才能肯定这次发送不会发生碰撞。 当发生碰撞时,站点要停止发送,等待一段时间再发送。这个时间采用 **截断二进制指数退避算法** 来确定,从离散的整数集合 {0, 1, .., (2k-1)} 中随机取出一个数,记作 r,然后取 r 倍的争用期作为重传等待时间。 -## 扩展局域网 * +## 扩展局域网* ### 1. 在物理层进行扩展 @@ -312,49 +320,48 @@ CSMA/CD 表示载波监听多点接入 / 碰撞检测。 集线器是一种共享式的传输设备,意味着同一时刻只能传输一组数据帧。 -

+

### 2. 在链路层进行扩展 -最开始使用的是网桥,它收到一个帧时,根据帧的 MAC 地址,查找网桥中的地址表,确定将帧转发的接口。 +最开始使用的是网桥,它收到一个帧时,根据帧的 MAC 地址,查找网桥中的地址表,确定帧转发的接口。 网桥不是共享式设备,因此性能比集线器这种共享式设备更高。 交换机的问世很快就淘汰了网桥,它实质上是一个多接口网桥,而网桥是两接口。交换机的每个接口都能直接与一个主机或者另一个交换机相连,并且一般都工作在全双工方式。 -交换机具有自学习能力,学习的是交换表的内容,交换表中存储着 MAC 地址到接口的映射。下图中,交换机有 4 个接口,主机 A 向主机 B 发送数据帧时,交换机把主机 A 到接口 1 的映射写入交换表中。为了发送数据帧到 B,先查交换表,此时没有主机 B 的表项,那么主机 A 就发送广播帧,主机 C 和主机 D 会丢弃该帧,主机 B 收下之后,查找交换表得到主机 A 映射的接口为 1,因此就把帧发送给主机 A,同时交换机添加主机 B 到接口 3 的映射。 +交换机具有自学习能力,学习的是交换表的内容。交换表中存储着 MAC 地址到接口的映射。下图中,交换机有 4 个接口,主机 A 向主机 B 发送数据帧时,交换机把主机 A 到接口 1 的映射写入交换表中。为了发送数据帧到 B,先查交换表,此时没有主机 B 的表项,那么主机 A 就发送广播帧,主机 C 和主机 D 会丢弃该帧。主机 B 收下之后,查找交换表得到主机 A 映射的接口为 1,就发送数据帧到接口 1,同时交换机添加主机 B 到接口 3 的映射。 -

+

### 3. 虚拟局域网 虚拟局域网可以建立与物理位置无关的逻辑组,只有在同一个虚拟局域网中的成员才会收到链路层广播信息,例如下图中 (A1, A2, A3, A4) 属于一个虚拟局域网,A1 发送的广播会被 A2、A3、A4 收到,而其它站点收不到。 -

+

-## MAC 层 * +## MAC 层* MAC 地址是 6 字节(48 位)的地址,用于唯一标识网络适配器(网卡),一台主机拥有多少个适配器就有多少个 MAC 地址,例如笔记本电脑普遍存在无线网络适配器和有线网络适配器。 -

+

+ +在 MAC 帧中: - **类型** :标记上层使用的协议; - - **数据** :长度在 46-1500 之间,如果太小则需要填充; - - **FCS** :帧检验序列,使用的是 CRC 检验方法; - - **前同步码** :只是为了计算 FCS 临时加入的,计算结束之后会丢弃。 -# 四、网络层 * +# 四、网络层* -## 网际协议 IP 概述 +## 概述 因为网络层是整个互联网的核心,因此应当让网络层尽可能简单。网络层向上只提供简单灵活的、无连接的、尽最大努力交互的数据报服务。 使用 IP 协议,可以把异构的物理网络连接起来,使得在网络层看起来好像是一个统一的网络。 -

+

与 IP 协议配套使用的还有三个协议: @@ -362,15 +369,15 @@ MAC 地址是 6 字节(48 位)的地址,用于唯一标识网络适配器 2. 网际控制报文协议 ICMP(Internet Control Message Protocol) 3. 网际组管理协议 IGMP(Internet Group Management Protocol) -

+

## IP 数据报格式 -

+

- **版本** : 有 4(IPv4)和 6(IPv6)两个值; -- **首部长度** : 占 4 位,因此最大值为 15。值为 1 表示的是 1 个 32 位字的长度,也就是 4 字节。因为首部固定长度为 20 字节,因此该值最小为 5。如果可选部分的长度不是 4 字节的整数倍,就用尾部的填充部分来填充。 +- **首部长度** : 占 4 位,因此最大值为 15。值为 1 表示的是 1 个 32 位字的长度,也就是 4 字节。因为首部固定长度为 20 字节,因此该值最小为 5。如果可选字段的长度不是 4 字节的整数倍,就用尾部的填充部分来填充。 - **区分服务** : 用来获得更好的服务,一般情况下不使用。 @@ -380,7 +387,7 @@ MAC 地址是 6 字节(48 位)的地址,用于唯一标识网络适配器 - **片偏移** : 和标识符一起,用于发生分片的情况。片偏移的单位为 8 字节。 -

+

- **生存时间** :TTL,它的存在是为了防止无法交付的数据报在互联网中不断兜圈子。以路由器跳数为单位,当 TTL 为 0 时就丢弃数据报。 @@ -388,21 +395,21 @@ MAC 地址是 6 字节(48 位)的地址,用于唯一标识网络适配器 - **首部检验和** :因为数据报每经过一个路由器,都要重新计算检验和,因此检验和不包含数据部分可以减少计算的工作量。 -## IP 地址编址 +## IP 地址编址方式 IP 地址的编址方式经历了三个历史阶段: -1. 分类; -2. 子网划分; -3. 无分类。 +1. 分类 +2. 子网划分 +3. 无分类 ### 1. 分类 -由两部分组成,网络号和主机号,其中不同类别具有不同的网络号长度,并且是固定的。 +由两部分组成,网络号和主机号,其中不同分类具有不同的网络号长度,并且是固定的。 IP 地址 ::= {< 网络号 >, < 主机号 >} -

+

### 2. 子网划分 @@ -430,48 +437,38 @@ CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为 网络层实现主机之间的通信,而链路层实现具体每段链路之间的通信。因此在通信过程中,IP 数据报的源地址和目的地址始终不变,而 MAC 地址随着链路的改变而改变。 -

+

## 地址解析协议 ARP 实现由 IP 地址得到 MAC 地址。 -

+

每个主机都有一个 ARP 高速缓存,里面有本局域网上的各主机和路由器的 IP 地址到硬件地址的映射表。 如果主机 A 知道主机 B 的 IP 地址,但是 ARP 高速缓存中没有该 IP 地址到 MAC 地址的映射,此时主机 A 通过广播的方式发送 ARP 请求分组,主机 B 收到该请求后会发送 ARP 响应分组给主机 A 告知其 MAC 地址,随后主机 A 向其高速缓存中写入主机 B 的 IP 地址到硬件地址的映射。 -

+

## 路由器的结构 -路由器从功能上可以划分为两大部分:路由选择和分组转发。 +路由器从功能上可以划分为:路由选择和分组转发。 -分组转发部分由三部分组成:交换结构、一组输入端口和一组输出端口。 - -

- -交换结构的交换网络有以下三种实现方式: - -

+分组转发结构由三个部分组成:交换结构、一组输入端口和一组输出端口。 +

## 路由器分组转发流程 -1. 从数据报的首部提取目的主机的 IP 地址 D,得到目的网络地址 N。(路由表项是网络号而不是 IP 地址,这样做大大减少了路由表条目数量); - +1. 从数据报的首部提取目的主机的 IP 地址 D,得到目的网络地址 N。 2. 若 N 就是与此路由器直接相连的某个网络地址,则进行直接交付; - 3. 若路由表中有目的地址为 D 的特定主机路由,则把数据报传送给表中所指明的下一跳路由器; - 4. 若路由表中有到达网络 N 的路由,则把数据报传送给路由表中所指明的下一跳路由器; - 5. 若路由表中有一个默认路由,则把数据报传送给路由表中所指明的默认路由器; - 6. 报告转发分组出错。 -

+

## 路由选择协议 @@ -484,7 +481,7 @@ CIDR 的地址掩码可以继续称为子网掩码,子网掩码首 1 长度为 1. 内部网关协议 IGP(Interior Gateway Protocol):在 AS 内部使用,如 RIP 和 OSPF。 2. 外部网关协议 EGP(External Gateway Protocol):在 AS 之间使用,如 BGP。 -

+

### 1. 内部网关协议 RIP @@ -524,17 +521,17 @@ BGP 只能寻找一条比较好的路由,而不是最佳路由。它采用路 每个 AS 都必须配置 BGP 发言人,通过在两个相邻 BGP 发言人之间建立 TCP 连接来交换路由信息。 -

+

## 网际控制报文协议 ICMP ICMP 是为了更有效地转发 IP 数据报和提高交付成功的机会。它封装在 IP 数据报中,但是不属于高层协议。 -

+

ICMP 报文分为差错报告报文和询问报文。 -

+

## 分组网间探测 PING @@ -549,7 +546,7 @@ PING 的过程: 在一对多的通信中,多播不需要将分组复制多份,从而大大节约网络资源。 -

+

## 虚拟专用网 VPN @@ -565,7 +562,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 下图中,场所 A 和 B 的通信部经过互联网,如果场所 A 的主机 X 要和另一个场所 B 的主机 Y 通信,IP 数据报的源地址是 10.1.0.1,目的地址是 10.2.0.3。数据报先发送到与互联网相连的路由器 R1,R1 对内部数据进行加密,然后重新加上数据报的首部,源地址是路由器 R1 的全球地址 125.1.2.3,目的地址是路由器 R2 的全球地址 194.4.5.6。路由器 R2 收到数据报后将数据部分进行解密,恢复原来的数据报,此时目的地址为 10.2.0.3,就交付给 Y。 -

+

## 网络地址转换 NAT @@ -573,9 +570,9 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 在以前,NAT 将本地 IP 和全球 IP 一一对应,这种方式下拥有 n 个全球 IP 地址的专用网内最多只可以同时有 n 台主机接入互联网。为了更有效地利用全球 IP 地址,现在常用的 NAT 转换表把运输层的端口号也用上了,使得多个专用网内部的主机共用一个全球 IP 地址。使用端口号的 NAT 也叫做网络地址与端口转换 NAPT。 -

+

-# 五、运输层 * +# 五、运输层* 网络层只把分组发送到目的主机,但是真正通信的并不是主机而是主机中的进程。 @@ -589,13 +586,13 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 ## UDP 首部格式 -

+

首部字段只有 8 个字节,包括源端口、目的端口、长度、检验和。12 字节的伪首部是为了计算检验和临时添加的。 ## TCP 首部格式 -

+

- **序号** :用于对字节流进行编号,例如序号为 301,表示第一个字节的编号为 301,如果携带的数据长度为 100 字节,那么下一个报文段的序号应为 401。 @@ -613,7 +610,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 ## TCP 的三次握手 -

+

假设 A 为客户端,B 为服务器端。 @@ -629,7 +626,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 ## TCP 的四次挥手 -

+

以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。 @@ -651,7 +648,7 @@ VPN 使用公用的互联网作为本机构各专用网之间的通信载体。 ## TCP 滑动窗口 -

+

窗口是缓存的一部分,用来暂时存放字节流。发送方和接收方各有一个窗口,接收方通过 TCP 报文段中的窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。 @@ -683,7 +680,7 @@ TCP 使用超时重传来实现可靠传输:如果一个已经发送的报文 如果网络出现拥塞,分组将会丢失,此时发送方会继续重传,从而导致网络拥塞程度更高。因此当出现拥塞时,应当控制发送方的速率。这一点和流量控制很像,但是出发点不同。流量控制是为了让接收方能来得及接受,而拥塞控制是为了降低整个网络的拥塞程度。 -

+

TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、快重传、快恢复。发送方需要维护有一个叫做拥塞窗口(cwnd)的状态变量。注意拥塞窗口与发送方窗口的区别,拥塞窗口只是一个状态变量,实际决定发送方能发送多少数据的是发送方窗口。 @@ -692,7 +689,7 @@ TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、 1. 接收方有足够大的接收缓存,因此不会发生流量控制; 2. 虽然 TCP 的窗口基于字节,但是这里设窗口的大小单位为报文段。 -

+

### 1. 慢开始与拥塞避免 @@ -710,9 +707,9 @@ TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、 在这种情况下,只是丢失个别报文段,而不是网络拥塞,因此执行快恢复,令 ssthresh = cwnd / 2 ,cwnd = ssthresh,注意到此时直接进入拥塞避免。 -

+

-# 六、应用层 * +# 六、应用层* ## 域名系统 DNS @@ -724,9 +721,9 @@ TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、 一个域名由多个层次构成,从上层到下层分别为顶级域名、二级域名、三级域名以及四级域名。所有域名可以画成一颗域名树。 -

+

-

+

域名服务器可以分为以下四类: @@ -737,11 +734,11 @@ TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、 区和域的概念不同,可以在一个域中划分多个区。图 b 在域 abc.com 中划分了两个区:abc.com 和 y.abc.com -

+

因此就需要两个权限域名服务器: -

+

### 2. 解析过程 @@ -749,13 +746,13 @@ TCP 主要通过四种算法来进行拥塞控制:慢开始、拥塞避免、 迭代的方式下,本地域名服务器向一个域名服务器解析请求解析之后,结果返回到本地域名服务器,然后本地域名服务器继续向其它域名服务器请求解析;而递归地方式下,结果不是直接返回的,而是继续向前请求解析,最后的结果才会返回。 -

+

## 文件传输协议 FTP FTP 在运输层使用 TCP,并且需要建立两个并行的 TCP 连接:控制连接和数据连接。控制连接在整个会话期间一直保持打开,而数据连接在数据传送完毕之后就关闭。控制连接使用端口号 21,数据连接使用端口号 20。 -

+

## 远程终端协议 TELNET @@ -771,7 +768,7 @@ TELNET 可以适应许多计算机和操作系统的差异,例如不同操作 一个电子邮件系统由三部分组成:用户代理、邮件服务器以及邮件发送协议和读取协议。其中发送协议常用 SMTP,读取协议常用 POP3 和 IMAP。 -

+

### 1. POP3 @@ -785,7 +782,7 @@ IMAP 协议中客户端和服务器上的邮件保持同步,如果不去手动 SMTP 只能发送 ASCII 码,而互联网邮件扩充 MIME 可以发送二进制文件。MIME 并没有改动或者取代 SMTP,而是增加邮件主题的结构,定义了非 ASCII 码的编码规则。 -

+

## 动态主机配置协议 DHCP diff --git a/pics/02986f62-c641-44a8-a55f-983581490e0c.png b/pics/02986f62-c641-44a8-a55f-983581490e0c.png new file mode 100644 index 00000000..96726ebc Binary files /dev/null and b/pics/02986f62-c641-44a8-a55f-983581490e0c.png differ diff --git a/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png b/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png new file mode 100644 index 00000000..395d9201 Binary files /dev/null and b/pics/0a9f4125-b6ab-4e94-a807-fd7070ae726a.png differ diff --git a/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png b/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png new file mode 100644 index 00000000..cb78d856 Binary files /dev/null and b/pics/10bdf7bf-0daa-4a26-b927-f142b3f8e72b.png differ diff --git a/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg b/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg new file mode 100644 index 00000000..7041fd5f Binary files /dev/null and b/pics/10f5e35b-1c71-4717-9e80-47f259702642.jpg differ diff --git a/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg b/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg new file mode 100644 index 00000000..48a91211 Binary files /dev/null and b/pics/1ab49e39-012b-4383-8284-26570987e3c4.jpg differ diff --git a/pics/21041ec2-babb-483f-bf47-8b8148eec162.png b/pics/21041ec2-babb-483f-bf47-8b8148eec162.png new file mode 100644 index 00000000..7de9b57a Binary files /dev/null and b/pics/21041ec2-babb-483f-bf47-8b8148eec162.png differ diff --git a/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png b/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png new file mode 100644 index 00000000..5fccbd1c Binary files /dev/null and b/pics/23ba890e-e11c-45e2-a20c-64d217f83430.png differ diff --git a/pics/265a355d-aead-48aa-b455-f33b62fe729f.png b/pics/265a355d-aead-48aa-b455-f33b62fe729f.png new file mode 100644 index 00000000..bb564f6e Binary files /dev/null and b/pics/265a355d-aead-48aa-b455-f33b62fe729f.png differ diff --git a/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg b/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg new file mode 100644 index 00000000..8676c440 Binary files /dev/null and b/pics/276c31df-3b28-4ac2-b006-1e80fc86a64f.jpg differ diff --git a/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png b/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png new file mode 100644 index 00000000..c2cf9d1b Binary files /dev/null and b/pics/3939369b-3a4a-48a0-b9eb-3efae26dd400.png differ diff --git a/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png b/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png new file mode 100644 index 00000000..98327bba Binary files /dev/null and b/pics/426df589-6f97-4622-b74d-4a81fcb1da8e.png differ diff --git a/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png b/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png new file mode 100644 index 00000000..32fb94aa Binary files /dev/null and b/pics/45e0e0bf-386d-4280-a341-a0b9496c7674.png differ diff --git a/pics/5144a411-0e46-4a84-a179-c9ad3240418f.png b/pics/5144a411-0e46-4a84-a179-c9ad3240418f.png new file mode 100644 index 00000000..a0a9b6ce Binary files /dev/null and b/pics/5144a411-0e46-4a84-a179-c9ad3240418f.png differ diff --git a/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg b/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg new file mode 100644 index 00000000..809abead Binary files /dev/null and b/pics/52e1af6f-3a7a-4bee-aa8f-fcb5dacebe40.jpg differ diff --git a/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png b/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png new file mode 100644 index 00000000..a61a7dc4 Binary files /dev/null and b/pics/5999e5de-7c16-4b52-b3aa-6dc7b58c7894.png differ diff --git a/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png b/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png new file mode 100644 index 00000000..68310502 Binary files /dev/null and b/pics/5aa82b89-f266-44da-887d-18f31f01d8ef.png differ diff --git a/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg b/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg new file mode 100644 index 00000000..eec226c5 Binary files /dev/null and b/pics/66192382-558b-4b05-a35d-ac4a2b1a9811.jpg differ diff --git a/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg b/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg new file mode 100644 index 00000000..03b7f3da Binary files /dev/null and b/pics/69f16984-a66f-4288-82e4-79b4aa43e835.jpg differ diff --git a/pics/750501be-6b8a-4cb5-a807-371a218ee612.png b/pics/750501be-6b8a-4cb5-a807-371a218ee612.png new file mode 100644 index 00000000..40aa7233 Binary files /dev/null and b/pics/750501be-6b8a-4cb5-a807-371a218ee612.png differ diff --git a/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg b/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg new file mode 100644 index 00000000..bc5ddb98 Binary files /dev/null and b/pics/77f81379-3987-4036-8d7c-93a4dcf7b05d.jpg differ diff --git a/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg b/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg new file mode 100644 index 00000000..919a0e58 Binary files /dev/null and b/pics/7b038838-c75b-4538-ae84-6299386704e5.jpg differ diff --git a/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg b/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg new file mode 100644 index 00000000..d4380524 Binary files /dev/null and b/pics/7b68b142-9489-44f6-87b0-4cb5c6431e63.jpg differ diff --git a/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png b/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png new file mode 100644 index 00000000..ac453eeb Binary files /dev/null and b/pics/8006a450-6c2f-498c-a928-c927f758b1d0.png differ diff --git a/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg b/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg new file mode 100644 index 00000000..4b911193 Binary files /dev/null and b/pics/85c05fb1-5546-4c50-9221-21f231cdc8c5.jpg differ diff --git a/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png b/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png new file mode 100644 index 00000000..7b85c49a Binary files /dev/null and b/pics/92ad9bae-7d02-43ba-8115-a9d6f530ca28.png differ diff --git a/pics/94589319-975f-490b-8bae-90b3a4953559.png b/pics/94589319-975f-490b-8bae-90b3a4953559.png new file mode 100644 index 00000000..fab53e3d Binary files /dev/null and b/pics/94589319-975f-490b-8bae-90b3a4953559.png differ diff --git a/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png b/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png new file mode 100644 index 00000000..49da824e Binary files /dev/null and b/pics/9cd0ae20-4fb5-4017-a000-f7d3a0eb3529.png differ diff --git a/pics/MultiNode-SessionReplication.jpg b/pics/MultiNode-SessionReplication.jpg new file mode 100644 index 00000000..0223bd80 Binary files /dev/null and b/pics/MultiNode-SessionReplication.jpg differ diff --git a/pics/MultiNode-SpringSession.jpg b/pics/MultiNode-SpringSession.jpg new file mode 100644 index 00000000..38d56e2c Binary files /dev/null and b/pics/MultiNode-SpringSession.jpg differ diff --git a/pics/MultiNode-StickySessions.jpg b/pics/MultiNode-StickySessions.jpg new file mode 100644 index 00000000..a7e1c6aa Binary files /dev/null and b/pics/MultiNode-StickySessions.jpg differ diff --git a/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg b/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg new file mode 100644 index 00000000..4ff577e2 Binary files /dev/null and b/pics/a6026bb4-3daf-439f-b1ec-a5a24e19d2fb.jpg differ diff --git a/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg b/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg new file mode 100644 index 00000000..b7502831 Binary files /dev/null and b/pics/b9d79a5a-e7af-499b-b989-f10483e71b8b.jpg differ diff --git a/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg b/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg new file mode 100644 index 00000000..17a2e9bf Binary files /dev/null and b/pics/c3369072-c740-43b0-b276-202bd1d3960d.jpg differ diff --git a/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg b/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg new file mode 100644 index 00000000..3eb79406 Binary files /dev/null and b/pics/c5022dd3-be22-4250-b9f6-38ae984a04d7.jpg differ diff --git a/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png b/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png new file mode 100644 index 00000000..27f2b742 Binary files /dev/null and b/pics/cbf50eb8-22b4-4528-a2e7-d187143d57f7.png differ diff --git a/pics/cookiedata.png b/pics/cookiedata.png new file mode 100644 index 00000000..a425fca6 Binary files /dev/null and b/pics/cookiedata.png differ diff --git a/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg b/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg new file mode 100644 index 00000000..90953621 Binary files /dev/null and b/pics/d1f81ac3-9fdb-4371-a49d-ca84917aa89f.jpg differ diff --git a/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png b/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png new file mode 100644 index 00000000..4f62e6f5 Binary files /dev/null and b/pics/d4eef1e2-5703-4ca4-82ab-8dda93d6b81f.png differ diff --git a/pics/d5659bcf-5ddf-4692-bfe5-f6b480479120.png b/pics/d5659bcf-5ddf-4692-bfe5-f6b480479120.png new file mode 100644 index 00000000..e3190ede Binary files /dev/null and b/pics/d5659bcf-5ddf-4692-bfe5-f6b480479120.png differ diff --git a/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg b/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg new file mode 100644 index 00000000..2a95d92d Binary files /dev/null and b/pics/ddcf2327-8d84-425d-8535-121a94bcb88d.jpg differ diff --git a/pics/df648536-a107-48cd-a615-77b7a9b4025f.png b/pics/df648536-a107-48cd-a615-77b7a9b4025f.png new file mode 100644 index 00000000..e709f110 Binary files /dev/null and b/pics/df648536-a107-48cd-a615-77b7a9b4025f.png differ diff --git a/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg b/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg new file mode 100644 index 00000000..a07e736d Binary files /dev/null and b/pics/ea5f3efe-d5e6-499b-b278-9e898af61257.jpg differ diff --git a/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png b/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png new file mode 100644 index 00000000..8f797bdf Binary files /dev/null and b/pics/f0e35b7a-2948-488a-a5a9-97d3f6b5e2d7.png differ diff --git a/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg b/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg new file mode 100644 index 00000000..9dc7a1d5 Binary files /dev/null and b/pics/f3bfe11f-9cba-4ff2-8cc6-629068408a80.jpg differ diff --git a/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png b/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png new file mode 100644 index 00000000..300b6e06 Binary files /dev/null and b/pics/f8b16d1e-7363-4544-94d6-4939fdf849dc.png differ