From 4c4806739580862c3688d5b72d5071ef338d5439 Mon Sep 17 00:00:00 2001 From: yinkanglong_lab Date: Thu, 8 Apr 2021 19:20:41 +0800 Subject: [PATCH] =?UTF-8?q?=E8=85=BE=E8=AE=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- C++/面试/12.nullptr、NULL、0.md | 2 +- 工作日志/2021年4月7日-简历说明.md | 3 +- 工作日志/2021年4月9日-实习复习计划.md | 11 +- 操作系统/2.5 进程与线程.md | 1 + 操作系统/4.3 分页存储管理.md | 42 +++++--- 操作系统/5.1 五种IO模型.md | 115 +++++++++++++++------ 操作系统/附录3 互斥量、信号量、条件变量.md | 5 +- 操作系统/附录8 同步异步、阻塞非阻塞.md | 2 +- 计算机网络/面试问题整理.md | 10 +- 9 files changed, 126 insertions(+), 65 deletions(-) diff --git a/C++/面试/12.nullptr、NULL、0.md b/C++/面试/12.nullptr、NULL、0.md index 01f9c6af..c845a5db 100644 --- a/C++/面试/12.nullptr、NULL、0.md +++ b/C++/面试/12.nullptr、NULL、0.md @@ -19,7 +19,7 @@ foo_t *f = NULL; ``` ### C++中的NULL -* C++中void* 不能进行前置类型转换成其他类型的NULL,所以int* 类型的空指针,不能使用void* 代替,则原来的宏定义无法使用。 +* C++中void* 不能进行强制类型转换成其他类型的NULL,所以int* 类型的空指针,不能使用void* 代替,则原来的宏定义无法使用。 * C++中使用0,来表示空指针。 ``` #ifdef __cplusplus ---简称:cpp c++ 文件 diff --git a/工作日志/2021年4月7日-简历说明.md b/工作日志/2021年4月7日-简历说明.md index b2dc20f0..178d1641 100644 --- a/工作日志/2021年4月7日-简历说明.md +++ b/工作日志/2021年4月7日-简历说明.md @@ -76,8 +76,7 @@ ### ~~补充项目——企业级开发JavaEE项目考试系统~~ > 因为是java项目,等日后学完java再写 -### ~~补充项目———项目组织管理图书馆里系统开发~~ -> 因为是java项目。 + ### ~~补充项目——windows通信编程。多人聊天室~~ * 项目概述:单人项目开发。 * 主要工作:MFC开发界面、windows网络通信。 diff --git a/工作日志/2021年4月9日-实习复习计划.md b/工作日志/2021年4月9日-实习复习计划.md index 23453cf2..46950786 100644 --- a/工作日志/2021年4月9日-实习复习计划.md +++ b/工作日志/2021年4月9日-实习复习计划.md @@ -2,13 +2,16 @@ ### **腾讯面试前复习** - 基础知识复习 - - [ ] 数据库 - - [ ] 计算机网络 - - [ ] 操作系统(最后一遍搞清楚同步通信、IO过程相关的问题提) + - [x] 数据库 + - [x] 计算机网络 + - [x] 操作系统(最后一遍搞清楚同步通信、IO过程相关的问题提) + - [x] C++ + - [x] 项目经历 + - [ ] 把所有项目上传到gitee和github并开源 - 腾讯要求复习 - [x] nosql/redis非关系型数据库 - [ ] Hadoop/spark 分布式数据处理(没时间了,等下一轮吧) - 腾讯面经复习 - - [ ] 针对腾讯的面试笔试问题进行复习 + - [x] 针对腾讯的面试笔试问题进行复习 ## 收获 \ No newline at end of file diff --git a/操作系统/2.5 进程与线程.md b/操作系统/2.5 进程与线程.md index 07866fb0..09608612 100644 --- a/操作系统/2.5 进程与线程.md +++ b/操作系统/2.5 进程与线程.md @@ -11,6 +11,7 @@ ### 线程 * 线程是**独立调度的基本单位**。一个进程中可以有多个线程,它们共享进程资源。 +* 线程栈是在进程的堆中分配栈空间,每个线程拥有独立的栈空间,为了避免线程之间的栈空间踩踏,线程栈之间还会有以小块guardsize用来隔离保护各自的栈空间,一旦另一个线程踏入到这个隔离区,就会引发段错误。 * QQ 和浏览器是两个进程,浏览器进程里面有很多线程,例如 HTTP 请求线程、事件响应线程、渲染线程等等,线程的并发执行使得在浏览器中点击一个新链接从而发起 HTTP 请求时,浏览器还可以响应用户的其它事件。 ![](image/2021-03-29-22-53-11.png) diff --git a/操作系统/4.3 分页存储管理.md b/操作系统/4.3 分页存储管理.md index cdcdecc4..ebb31cc9 100644 --- a/操作系统/4.3 分页存储管理.md +++ b/操作系统/4.3 分页存储管理.md @@ -1,5 +1,7 @@ # 4.2 分页存储管理方式 +> 参考文献 +> * [https://www.cnblogs.com/fkissx/p/4712959.html](https://www.cnblogs.com/fkissx/p/4712959.html) ## 1 页面与页表 ### 页面和物理块 @@ -79,14 +81,9 @@ 1. 总是淘汰最先调入主存的那一页,或者说主存驻留时间最长的那一页(常驻的除外) 2. 选择换出的页面是最先进入的页面。该算法会将那些经常被访问的页面换出,导致缺页率升高。 3. 模拟的是程序执行的顺序性,有一定合理性 -### 4.3 第二次机会算法 -FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改: -当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。 -![](image/2021-04-06-00-21-08.png) - -### 4.4 最近最少用LRU,Least Recently Used +### 4.3 最近最少用LRU,Least Recently Used 1. 为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。 2. 因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。 @@ -97,16 +94,7 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问 ![](image/2021-04-06-00-17-39.png) - - -### 4.5 最不常用LFU -1. 淘汰最近一段时间内访问次数较少的页面,对OPT的模拟性比LRU更好 -2. 基于时间间隔中断,并给每一页设置一个计数器 -3. 时间间隔中断发生后,所有计数器清0 -4. 每访问页1次就给计数器加1 -5. 选择计数值最小的页面淘汰 - -### 4.6 最近未使用NRU, Not Recently Used +### 4.4 时钟CLOCK==最近未使用NRU, Not Recently Used 每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类: @@ -119,7 +107,12 @@ FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问 NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁使用的干净页面(R=1,M=0)。 -### 4.7 时钟CLOCK +> 算法执行如下操作步骤: + +从指针的当前位置开始,扫描帧缓冲区。在这次扫描过程中,对使用位不做任何修改。选择遇到的第一个帧(u=0, m=0)用于替换。 +如果第1)步失败,则重新扫描,查找(u=0, m=1)的帧。选择遇到的第一个这样的帧用于替换。在这个扫描过程中,对每个跳过的帧,把它的使用位设置成0。 +如果第2)步失败,指针将回到它的最初位置,并且集合中所有帧的使用位均为0。重复第1步,并且如果有必要,重复第2步。这样将可以找到供替换的帧 +> 第二个解析 1. 第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。 2. 采用循环队列机制构造页面队列,形成了一个类似于钟表面的环形表 @@ -134,6 +127,21 @@ NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁 ![](image/2021-04-06-00-22-23.png) +### 4.3 第二次机会算法 + +FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改: + +当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。 +![](image/2021-04-06-00-21-08.png) + + + +### 4.5 最不常用LFU +1. 淘汰最近一段时间内访问次数较少的页面,对OPT的模拟性比LRU更好 +2. 基于时间间隔中断,并给每一页设置一个计数器 +3. 时间间隔中断发生后,所有计数器清0 +4. 每访问页1次就给计数器加1 +5. 选择计数值最小的页面淘汰 ## 5 反置页表 ### 提出: 1. 页面及相关硬件机制在地址转换、存储保护、虚拟地址访问中发挥了关键作用 diff --git a/操作系统/5.1 五种IO模型.md b/操作系统/5.1 五种IO模型.md index a029134c..8c430067 100644 --- a/操作系统/5.1 五种IO模型.md +++ b/操作系统/5.1 五种IO模型.md @@ -86,20 +86,24 @@ ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr * > select/poll/epoll 都是 I/O 多路复用的具体实现,select 出现的最早,之后是 poll,再是 epoll。 -### select +## 2.1 select +* select 允许应用程序监视一组文件描述符,等待一个或者多个描述符成为就绪状态,从而完成 I/O 操作。 + +### 函数说明 ```c int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); ``` -* select 允许应用程序监视一组文件描述符,等待一个或者多个描述符成为就绪状态,从而完成 I/O 操作。 - +* 参数 - fd_set 使用数组实现,数组大小使用 FD_SETSIZE 定义,所以只能监听少于 FD_SETSIZE 数量的描述符。有三种类型的描述符类型:readset、writeset、exceptset,分别对应读、写、异常条件的描述符集合。 - timeout 为超时参数,调用 select 会一直阻塞直到有描述符的事件到达或者等待的时间超过 timeout。 +* 返回值 - 成功调用返回结果大于 0,出错返回结果为 -1,超时返回结果为 0。 +### 代码实现 ```c fd_set fd_in, fd_out; struct timeval tv; @@ -138,26 +142,38 @@ else // output event on sock2 } ``` +### 运行机制 -### poll +* select()的机制中提供一种fd_set的数据结构,实际上是一个long类型的数组,每一个数组元素都能与一打开的文件句柄(不管是Socket句柄,还是其他文件或命名管道或设备句柄)建立联系,建立联系的工作由程序员完成,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。 +* 从流程上来看,使用select函数进行IO请求和同步阻塞模型没有太大的区别,甚至还多了添加监视socket,以及调用select函数的额外操作,效率更差。但是,使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才能达到这个目的。 +### select机制的问题 +* 每次调用select,都需要把fd_set集合从用户态拷贝到内核态,如果fd_set集合很大时,那这个开销也很大 +* 同时每次调用select都需要在内核遍历传递进来的所有fd_set,如果fd_set集合很大时,那这个开销也很大 +* 为了减少数据拷贝带来的性能损坏,内核对被监控的fd_set集合大小做了限制,并且这个是通过宏控制的,大小不可改变(限制为1024) + +## 2.2 poll + +* poll的机制与select类似,与select在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是poll没有最大文件描述符数量的限制。poll 的功能与 select 类似,也是等待一组描述符中的一个成为就绪状态。也就是说,poll只解决了上面的问题3,并没有解决问题1,2的性能开销问题。 + +### 函数说明 ```c int poll(struct pollfd *fds, unsigned int nfds, int timeout); -``` - -* poll 的功能与 select 类似,也是等待一组描述符中的一个成为就绪状态。 - -* poll 中的描述符是 pollfd 类型的数组,pollfd 的定义如下: - -```c +// poll 中的描述符是 pollfd 类型的数组,pollfd 的定义如下: struct pollfd { - int fd; /* file descriptor */ - short events; /* requested events */ - short revents; /* returned events */ - }; + int fd; /* file descriptor */ + short events; /* requested events */ + short revents; /* returned events */ +}; ``` +* 参数 + * struct pollfd *fds fds是一个struct pollfd类型的数组,用于存放需要检测其状态的socket描述符,并且调用poll函数之后fds数组不会被清空;一个pollfd结构体表示一个被监视的文件描述符,通过传递fds指示 poll() 监视多个文件描述符。其中,结构体的events域是监视该文件描述符的事件掩码,由用户来设置这个域,结构体的revents域是文件描述符的操作结果事件掩码,内核在调用返回时设置这个域 + * nfds_t nfds 记录数组fds中描述符的总数量 +* 返回值 + * int 函数返回fds集合中就绪的读、写,或出错的描述符数量,返回0表示超时,返回-1表示出错; +### 代码实现 ```c // The structure for two events struct pollfd fds[2]; @@ -193,34 +209,57 @@ else ### 比较 1. 功能。select 和 poll 的功能基本相同,不过在一些实现细节上有所不同。 - - - select 会修改描述符,而 poll 不会; - - select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此默认只能监听少于 1024 个描述符。如果要监听更多描述符的话,需要修改 FD_SETSIZE 之后重新编译;而 poll 没有描述符数量的限制; - - poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高。 - - 如果一个线程对某个描述符调用了 select 或者 poll,另一个线程关闭了该描述符,会导致调用结果不确定。 + - select 会修改描述符,而 poll 不会; + - select 的描述符类型使用数组实现,FD_SETSIZE 大小默认为 1024,因此默认只能监听少于 1024 个描述符。如果要监听更多描述符的话,需要修改 FD_SETSIZE 之后重新编译;而 poll 没有描述符数量的限制; + - poll 提供了更多的事件类型,并且对描述符的重复利用上比 select 高。 + - 如果一个线程对某个描述符调用了 select 或者 poll,另一个线程关闭了该描述符,会导致调用结果不确定。 2. 速度。select 和 poll 速度都比较慢,每次调用都需要将全部描述符从应用进程缓冲区复制到内核缓冲区。 3. 可移植性。几乎所有的系统都支持 select,但是只有比较新的系统支持 poll。 -### epoll +## 2.3 epoll +* epoll在Linux2.6内核正式提出,是基于事件驱动的I/O方式,相对于select来说,epoll没有描述符个数限制,使用一个文件描述符管理多个描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。 +### 函数说明 ```c int epoll_create(int size); int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event); int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout); + +struct epoll_event { + __uint32_t events; /* Epoll events */ + epoll_data_t data; /* User data variable */ +}; + +typedef union epoll_data { + void *ptr; + int fd; + __uint32_t u32; + __uint64_t u64; +} epoll_data_t; ``` - -* epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵红黑树上,通过回调函数内核会将 I/O 准备好的描述符加入到一个链表中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。 - -* 从上面的描述可以看出,epoll 只需要将描述符从进程缓冲区向内核缓冲区拷贝一次,并且进程不需要通过轮询来获得事件完成的描述符。 - -* epoll 仅适用于 Linux OS。 - -* epoll 比 select 和 poll 更加灵活而且没有描述符数量限制。 - +1. epoll_create 函数创建一个epoll句柄,参数size表明内核要监听的描述符数量。调用成功时返回一个epoll句柄描述符,失败时返回-1。 +2. epoll_ctl 函数注册要监听的事件类型。 + * epfd 表示epoll句柄 + * op 表示fd操作类型,有如下3种: + * EPOLL_CTL_ADD 注册新的fd到epfd中 + * EPOLL_CTL_MOD 修改已注册的fd的监听事件 + * EPOLL_CTL_DEL 从epfd中删除一个fd + * fd 是要监听的描述符 + * event 表示要监听的事件 +3. epoll_wait 函数等待事件的就绪,成功时返回就绪的事件数目,调用失败时返回 -1,等待超时返回 0。 + * epfd 是epoll句柄 + * events 表示从内核得到的就绪事件集合 + * maxevents 告诉内核events的大小 + * timeout 表示等待的超时事件 +### 原理 +* epoll_ctl() 用于向内核注册新的描述符或者是改变某个文件描述符的状态。已注册的描述符在内核中会被维护在一棵**红黑树**上,通过**回调函数**内核会将 I/O 准备好的描述符加入到一个**链表**中管理,进程调用 epoll_wait() 便可以得到事件完成的描述符。 +* 从上面的描述可以看出,epoll 只需要将描述符从**进程缓冲区向内核缓冲区拷贝一次**,并且进程不需要通过轮询来获得事件完成的描述符。 +* epoll 仅适用于 Linux OS。epoll 比 select 和 poll 更加灵活而且没有描述符数量限制。 * epoll 对多线程编程更有友好,一个线程调用了 epoll_wait() 另一个线程关闭了同一个描述符也不会产生像 select 和 poll 的不确定情况。 +### 代码实现 ```c // Create the epoll descriptor. Only one is needed per app, and is used to monitor all sockets. // The function argument is ignored (it was not before, but now it is), so put your favorite number here @@ -276,6 +315,8 @@ else 2. ET 模式。和 LT 模式不同的是,通知之后进程必须立即处理事件,下次再调用 epoll_wait() 时不会再得到事件到达的通知。 * 很大程度上减少了 epoll 事件被重复触发的次数,因此效率要比 LT 模式高。只支持 No-Blocking,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。 +* LT和ET原本应该是用于脉冲信号的,可能用它来解释更加形象。Level和Edge指的就是触发点,Level为只要处于水平,那么就一直触发,而Edge则为上升沿和下降沿的时候触发。比如:0->1 就是Edge,1->1 就是Level。 + ### 应用场景 @@ -284,4 +325,16 @@ else 2. poll 应用场景。poll 没有最大描述符数量的限制,如果平台支持并且对实时性要求不高,应该使用 poll 而不是 select。 -3. epoll 应用场景。只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。 \ No newline at end of file +3. epoll 应用场景。只需要运行在 Linux 平台上,有大量的描述符需要同时轮询,并且这些连接最好是长连接。需要同时监控小于 1000 个描述符,就没有必要使用 epoll,因为这个应用场景下并不能体现 epoll 的优势。需要监控的描述符状态变化多,而且都是非常短暂的,也没有必要使用 epoll。因为 epoll 中的所有描述符都存储在内核中,造成每次需要对描述符的状态改变都需要通过 epoll_ctl() 进行系统调用,频繁系统调用降低效率。并且 epoll 的描述符存储在内核,不容易调试。 + +## 3 对比 + +| | select | poll | epoll | +|---|---|---|---| +| 操作方式 | 遍历 | 遍历 | 回调 | +| 底层实现 | 数组 | 链表 | 红黑树 | +| IO效率 | 每次调用都进行线性遍历,时间复杂度为O(n) | 每次调用都进行线性遍历,时间复杂度为O(n) | 事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到readyList里面,时间复杂度O(1) | +| 最大连接数 | 1024(x86)或2048(x64) | 无上限 | 无上限 | +| fd拷贝 | 每次调用select,都需要把fd集合从用户态拷贝到内核态 | 每次调用poll,都需要把fd集合从用户态拷贝到内核态 | 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝 | + +* epoll是Linux目前大规模网络并发程序开发的首选模型。在绝大多数情况下性能远超select和poll。目前流行的高性能web服务器Nginx正式依赖于epoll提供的高效网络套接字轮询服务。但是,在并发连接不高的情况下,多线程+阻塞I/O方式可能性能更好。 diff --git a/操作系统/附录3 互斥量、信号量、条件变量.md b/操作系统/附录3 互斥量、信号量、条件变量.md index 897461f0..c90158c5 100644 --- a/操作系统/附录3 互斥量、信号量、条件变量.md +++ b/操作系统/附录3 互斥量、信号量、条件变量.md @@ -107,12 +107,11 @@ int pthread_mutex_unlock(pthread_mutex_t *mutex); * 返回值: 成功则返回0, 出错则返回错误编号. ### 互斥锁、信号量、条件变量对比 -1. 互斥锁要么被锁住,要么被解开,和二值信号量类似 -2. 互斥锁必须是谁上锁就由谁来解锁,而信号量的wait和post操作不必由同一个线程执行。 +1. 互斥锁要么被锁住,要么被解开,和二值信号量类似。互斥锁必须是谁上锁就由谁来解锁,而信号量的wait和post操作不必由同一个线程执行。 +2. 信号量有计数值,每次信号量post操作都会被记录,而条件变量在发送信号时,如果没有线程在等待该条件变量,那么信号将丢失。 3. sem_post是各种同步技巧中,唯一一个能在信号处理程序中安全调用的函数 4. 互斥锁是为上锁而优化的;条件变量是为等待而优化的;信号量既可用于上锁,也可用于等待,因此会有更多的开销和更高的复杂性 5. 互斥锁,条件变量都只用于同一个进程的各线程间,而信号量(有名信号量)可用于不同进程间的同步。当信号量用于进程间同步时,要求信号量建立在共享内存区。 -6. 信号量有计数值,每次信号量post操作都会被记录,而条件变量在发送信号时,如果没有线程在等待该条件变量,那么信号将丢失。 ## 3 读写锁 diff --git a/操作系统/附录8 同步异步、阻塞非阻塞.md b/操作系统/附录8 同步异步、阻塞非阻塞.md index 4eb20231..2668ffe7 100644 --- a/操作系统/附录8 同步异步、阻塞非阻塞.md +++ b/操作系统/附录8 同步异步、阻塞非阻塞.md @@ -58,7 +58,7 @@ ### 同步非阻塞 > 在此种方式下,用户进程发起一个IO操作以后边可返回做其它事情,但是用户进程需要时不时的询问IO操作是否就绪,这就要求用户进程不停的去询问,从而引入不必要的CPU资源浪费。其中目前JAVA的NIO就属于同步非阻塞IO。 -* poll机制。轮训IO信号,虽然没有阻塞,但是在循环中一直确认IO是否完成。效率很低。 +* 用户进程轮训IO信号,虽然没有阻塞,但是在循环中一直确认IO是否完成。效率很低。 ### 异步非阻塞通信 diff --git a/计算机网络/面试问题整理.md b/计算机网络/面试问题整理.md index dea131b5..5493062b 100644 --- a/计算机网络/面试问题整理.md +++ b/计算机网络/面试问题整理.md @@ -6,12 +6,10 @@ > 停止等待、回退N步、选择重传。 1. 校验和 2. 序号机制 -3. 确认机制和重传机制 -4. 超时重传机制。 -5. 滑动窗口和流水线技术 -6. 累计确认机制 -7. 选择重传机制 -8. 快速重传机制 +3. 确认机制和超时重传。 +4. 滑动窗口和流水线技术 +5. 累计确认机制 +6. 选择重传机制 ## 3. TCP的三次握手四次挥手 > 报文段类型SYN、FIN。状态迁移。序号变化。