数据结构
哈希函数
哈希函数是⼀种映射关系,根据关键词key,经过⼀定函数关系得到元素的位置。
常⻅的哈希函数构造⽅法:
1、直接定址法:
取关键字或关键字的某个线性函数值为散列地址。
H(key) = a * key + b,其中a和b为常数
2、除留余数法:
取关键字被某个不⼤于散列表⻓度 m 的数 p 求余,得到的作为散列地址。
H(key) = key % p, p < m
3、叠加法:
将关键字分为位数相同的⼏部分,然后取这⼏部分的叠加和(舍去进位)作为散列地址。
⽤于关键字位数较多,并且关键字中每⼀位上数字分布⼤致均匀。
4、随机数法:
选择⼀个随机函数,把关键字的随机函数值作为它的哈希值。
通常当关键字的⻓度不等时⽤这种⽅法。
当关键字是整数类型时就可以⽤除留余数法;如果关键字是⼩数类型,选择随机数法会⽐较好
哈希冲突
不同关键字通过相同哈希函数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。
哈希冲突的解决:
1、开放地址法(前提是散列表的⻓度⼤于等于所要存放的元素)
发⽣哈希冲突后,按照某⼀次序找到下⼀个空闲的单元,把冲突的元素放⼊。
2、线性探查法
从发⽣冲突的单元开始探查,依次查看下⼀个单元是否为空,如果到了最后⼀个单元还是空,那么再从表⾸依次判断。如此执⾏直到碰到了空闲的单元或者已经探查完所有单元。
3、平⽅探查法
从发⽣冲突的单元加上12,22,32,…,n2,直到遇到空闲的单元
4、双散列函数探查法
定义两个散列函数,分别为s1和s2,s1的算法和前⾯⼀致,s2取⼀个1~m-1之间并和m互为素数的数。s2作为步⻓。
更适合于造表前⽆法确定表⻓的情况;平均查找⻓度较短;适合结点规模较⼤时。
5、分离链接法:
将哈希值相同的元素构成⼀个链表,head放在散列表中。⼀般链表⻓度超过了8就转为红⿊树,⻓度少于6个就变为链表。
缺点:指针需要额外的空间
计算机基础
1、为什么需要进程间通信
1).数据传输
一个进程需要将它的数据发送给另一个进程。
2).资源共享
多个进程之间共享同样的资源。
3).通知事件
一个进程需要向另一个或一组进程发送消息,通知它们发生了某种事件。
4).进程控制
有些进程希望完全控制另一个进程的执行(如Debug进程),该控制进程希望能够拦截另一个进程的所有操作,并能够及时知道它的状态改变。
2、IPC原理
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信机制。
3、通信的方式
1)管道(无名管道)
1、特点
- 它是
半双工的(即数据只能在一个方向上流动)
,具有固定的读端和写端。 - 它
只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)
。 - 它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write
等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
2、原理
当一个管道建立时,调用pipe函数
在内核中开辟一块缓冲区用于通信,它会创建两个文件描述符
:fd[0]为读而打开,fd[1]为写而打开。要关闭管道只需将这两个文件描述符关闭即可。
2)FIFO(命名管道)
FIFO的出现解决了只能用于具有亲缘关系的IPC(PIPE)这一问题。
1、特点
- 命名管道是一个存在于
硬盘
上的文件,而管道是存在于内存
中的特殊文件。所以使用命名管道时必须先open将其打开
。 - 命名管道可以
在无关的进程之间交换数据
,与无名管道不同。
2、原理
FIFO不同于管道之处在于它提供了一个路径名与之关联
,以FIFO的文件形式存储文件系统中。命名管道是一个设备文件,因此即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO相互通信。
3)消息队列
1、特点
1.消息队列是消息的链表,具有特定的格式,存放在内存中并由消息队列标识符标识.
2.消息队列允许一个或多个进程向它写入或者读取消息.
3.与管道、命名管道一样,从消息队列中读出消息,消息队列中对应的数据都会被删除。
4.消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取.比FIFO更有优势。
2、缺点:
- 通信不及时,附件也有⼤⼩限制。
- 消息队列不适合⽐较⼤数据的传输,每个消息体都有⼀个最⼤⻓度的限制,同时所有队列所包含的全部消息体的总⻓度也是有上限。
- 消息队列通信过程中,存在⽤户态与内核态之间的数据拷⻉开销。
3、原理
A 进程要给 B 进程发送消息,A 进程把数据放在对应的消息队列后就可以正常返回了,B 进程需要的时候再去读取数据就可以了。
4)信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
1、特点
- 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
- 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
- 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
- 支持信号量组。
2、选择
Linux内核中解决并发控制的最常用方法是自旋锁和信号量:
相对低开销、短期、中断上下文加锁,优先考虑自旋锁;
相对长期、持有锁需要休眠的任务,优先考虑信号量;
3、信号量分类
5)共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
1、特点
- 共享内存是
最快
的一种 IPC,因为进程是直接对内存进行存取。 - 因为多个进程可以同时操作,所以
需要进行同步
。 - 信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
6)套接字(Sockets)
此方法主要用于在客户端和服务器之间通过网络进行通信。套接字是支持 TCP/IP 的网络通信的基本操作单元,可以看做是不同主机之间的进程进行双向通信的端点,简单的说就是通信的两方的一种约定,用套接字中的相关函数来完成通信过程。
4、进程
4.1 守护进程
守护进程是指在后台运⾏的,没有控制终端与它相连的进程。它独⽴于控制终端,周期性地执⾏某种任务。Linux 的⼤多数服务器就是⽤守护进程实现的。
4.2 僵⼫进程
多进程程序,⽗进程⼀般需要跟踪⼦进程的退出状态,当⼦进程退出,⽗进程在运⾏,⼦进程必须等到⽗进程捕获到了⼦进程的退出状态才真正结束。在⼦进程结束后,⽗进程读取状态前,此时⼦进程为僵⼫进程。
5、线程
1、线程如何减少开销
- 线程创建快,进程创建需要资源管理信息,⽐如内存管理信息和⽂件管理信息,⽽线程创建后是共享其所属进
程的资源管理信息; - 线程终⽌时间快,需要回收的仅有少ᰁ寄存器和私有的栈区;
- 线程切换快,因为线程切换仅涉及到少ᰁ寄存器和栈区,⽽进程上下⽂切换有CPU寄存器和程序计数器(CPU
上下⽂)、虚拟内存空间、⻚表切换、TLB失效等; - 线程因为创建时共享了其所述进程绝⼤多数资源,因此天⽣具有很好的线程间通信交互效率。
2、 线程间的同步的方式
互斥量(Mutex):采用互斥对象机制,只有拥有互斥对象的线程才有访问公共资源的权限。因为互斥对象只有一个,所以可以保证公共资源不会被多个线程同时访问。比如 Java 中的 synchronized 关键词和各种 Lock 都是这种机制。
信号量(Semphares) :它允许同一时刻多个线程访问同一资源,但是需要控制同一时刻访问此资源的最大线程数量
事件(Event) :Wait/Notify:通过通知操作的方式来保持多线程同步,还可以方便的实现多线程优先级的比较
3、 区别
6、互斥与同步
1、互斥锁(mutex)
互斥锁是⼀种简单的加锁的⽅法来控制对共享资源的访问,互斥锁只有两种状态,即加锁( lock )和解锁( unlock )
- 在访问共享资源后临界区域前,对互斥锁进⾏加锁。
- 在访问完成后释放互斥锁导上的锁。
- 对互斥锁进⾏加锁后,任何其他试图再次对互斥锁加锁的线程将会被阻塞,直到锁被释放。
2、死锁
必要条件:
1、互斥
2、占有和等待
3、不可抢占
4、循环等待
处理⽅法:
1、鸵⻦算法
把头埋在沙⼦⾥,假装根本没发⽣问题。
2、死锁检测与死锁恢复
3、从死锁中恢复
(1)利⽤抢占恢复
将进程挂起,强⾏取⾛资源给另⼀个进程使⽤,⽤完再放回
(2)利⽤回滚恢复
复位到更早的状态,那时它还没有取得所需的资源
(3)通过杀死进程恢复
杀掉环中的⼀个进程或多个,牺牲掉⼀个环外进程
4、死锁预防
破坏4个必要条件
5、死锁避免
3、读写锁
读写锁的特点:
- 如果有其它线程读数据,则允许其它线程执⾏读操作,但不允许写操作
- 如果有其它线程写数据,则其它线程都不允许读、写操作
读写锁分为读锁和写锁,规则如下:
- 如果某线程申请了读锁,其它线程可以再申请读锁,但不能申请写锁。
- 如果某线程申请了写锁,其它线程不能申请读锁,也不能申请写锁。
4、条件变量
与互斥锁不同,条件变量是⽤来等待⽽不是⽤来上锁的,条件变量本身不是锁!
条件变量⽤来⾃动阻塞⼀个线程,直到某特殊情况发⽣为⽌。通常条件变量和互斥锁同时使⽤。
条件变量的两个动作:
- 条件不满, 阻塞线程
- 当条件满⾜, 通知阻塞的线程开始⼯作
5、信号量
信号量⼴泛⽤于进程或线程间的同步和互斥,信号量本质上是⼀个⾮负的整数计数器,它被⽤来控制对公共资源的访问。
编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值⼤于 0 时,则可以访问,否则将阻塞。
计算机网络
为什么需要三次握⼿?
1、避免历史连接及服务端资源浪费
如果是两次握⼿,那么当客户端接收到服务端请求和确认报⽂后TCP连接建⽴。如果此时⽹络状态拥塞,客户端早期发送的请求连接报⽂未到达服务端⽽发⽣重传。后正常建⽴连接,传输完毕后断开连接。
但断开后早期的报⽂⼜被服务端所接收,那么服务端会误认为客户端再次发起连接,因此向客户端返回确认及请求连接报⽂,导致错误发⽣。并且由于此时客户端已断开,服务端⽆法收到客户端进⼀步的报⽂信息,造成服务端为为⽆效连接分配资源,造成浪费。
2、同步双⽅序列号
TCP中序列号和确认应答机制保障了传输的可靠性,因此当第⼆次握⼿时服务端向客户端发送请求报⽂时,需要客户端返回确认报⽂才保障双⽅序列号被可靠同步。如果仅有两次握⼿,只保证了客户端序列号的可靠性。
为什么挥⼿需要四次?
服务端通常需要等待完成数据的发送和处理,所以服务端的ACK和FIN⼀般都会分开发送,从⽽⽐三次握⼿导致多了⼀次。
半连接队列和全连接队列
- TCP三次握⼿时,客户端发送SYN到服务端,服务端收到之后,便回复ACK和SYN,状态由LISTEN变为SYN_RCVD,此时这个连接就被推⼊了SYN队列,即半连接队列。
- 当客户端回复ACK, 服务端接收后,三次握⼿就完成了。这时连接会等待被具体的应⽤取⾛,在被取⾛之前,它被推⼊ACCEPT队列,即全连接队列。
SYN攻击
攻击者伪造不同IP地址的SYN报⽂请求连接,服务端收到连接请求后分配资源,回复ACK+SYN包,但是由于IP地址是伪造的,⽆法收到回应,久⽽久之造成服务端半连接队列被占满,⽆法正常⼯作。
http 和 https 的区别
(1)http 和 https 都是基于 TCP 协议,但是 http 是使用明文传输,通讯内容可能被窃听和篡改,客户端也无法验证通讯方的身份,无法保证数据发送到正确的机器上;https 是在 http 的基础上加入了 SSL/TLS,可看成是添加了加密和认证机制的http,使用对称加密、非对称加密、证书等技术进行进行客户端与服务端的数据加密传输,最终达到保证整个通信的安全性。
(2)端口不同:http 使用的是80端口,https 使用的443端口
(3)资源消耗:和 http 通信相比,https通信会由于加解密处理消耗更多的CPU和内存资源
3.4 加密⽅式
- 对称加密:
只使⽤⼀个密钥,运算速度快,密钥必须保密,⽆法做到安全的密钥交换; - ⾮对称加密:
使⽤两个密钥,公钥可以任意分发⽽私钥保密,解决密钥交换问题,但速度慢。 - 混合加密:
实现信息的机密性,解决窃听⻛险;
HTTPS采⽤对称加密和⾮对称加密结合的[混合加密]⽅式。
通信建⽴前:
采⽤⾮对称加密的⽅式交换[会话密钥],后续不再使⽤⾮对称加密;
通信过程中:
全部使⽤对称加密的[会话密钥]⽅式,加密明⽂数据。
3.5 验证流程
- client发起HTTP请求,连接到server端⼝
- Server将⾃⼰的信息以数字证书的形式返回给client
(证书包含私钥公钥、⽹站地址、证书颁发机构、失效⽇期等) - 验证证书合法性
Server收到client响应后会先验证证书合法性(地址是否⼀致、是否过期)。 - ⽣成随机密码(RSA签名)
验证通过或⽤户接受了不受信任的证书,浏览器会⽣成⼀个随机的对称密钥(session key),并⽤公钥加密,让server⽤私钥解密,解密后⽤这个对称密钥进⾏传输; - ⽣成对称加密算法
验证server身份后,client⽣成⼀个对称加密的算法和对应密钥,以公钥加密后发送给server。(只有server的私钥才能对其进⾏解密)
SSL:Secure Socket Layer 安全套接字
TSL:Transport Layer Security 安全传输层协议
http/1.1和http/2.0的区别
(1)多路复用,做到同一个连接并发处理多个请求
:HTTP2.0 使用了多路复用的技术,做到同一个连接并发处理多个请求,并发请求的数量比HTTP1.1大了好几个数量级。
(2)支持首部压缩:HTTP2.0使用HPACK算法对header的数据进行压缩,这样数据体积小了,在网络上传输就会更快。
(3)服务器推送:当向支持HTTP2.0的web服务器请求时,服务器会顺便把客户端需要的资源一起推送到客户端,避免客户端再次创建连接发送请求到服务器端获取,这种方式非常合适加载静态资源。
(4)http2.0采用二进制而不是文本格式
。
HTTP优化⽅案
- TCP复⽤
将多个客户端的HTTP请求复⽤到⼀个服务端的TCP连接上 - HTTP复⽤
将⼀个客户端的多个HTTP请求复⽤到⼀个TCP连接进⾏处理 - 内容缓存
将经常⽤到的内容进⾏缓存,在下⼀次获取的时候,就可以直接在内存中获取相应的数据了 - 压缩
⽂本数据压缩,减少带宽 - SSL加速
- TCP缓冲
通过采⽤TCP缓冲技术,提⾼服务端响应时间和处理效率
常⻅状态码以及描述
code | 描述 |
---|---|
200 | 客户端请求成功 |
206 | partial content 服务器已经正确处理部分GET请求,实现断点续传或同时分⽚下载,该请求必须包含Range请求头来指示客户端期望得到的范围 |
301(永久᯿定向) | 该资源已被永久移动到新位置,将来任何对该资源的访问都要使⽤本响应返回的若⼲个URL之⼀ |
302(临时᯿定向) | 请求的资源现在临时从不同的URI中获得 |
304 | 如果客户端发送⼀个带条件的GET请求并且该请求已经被允许,⽽⽂档内容未被改变,则返回304,该响应不包含包体(即可直接使⽤缓存) |
400 | 请求报⽂语法有误,服务器⽆法识别 |
401 | 请求需要认证 |
403 | 请求的对应资源禁⽌被访问 |
404 | 服务器⽆法找到对应资源 |
500 | 服务器内部错误 |
503 | 服务器正忙 |
DNS解析
DNS主要通过UDP通信
DNS协议⽤来将域名转换为IP地址,也可将IP地址转换为相应的域名地址。
浏览器查询URL对应IP:浏览器缓存→操作系统缓存→路由器缓存;
三种类型的DNS服务器:根DNS服务器、顶级域DNS服务器、权威DNS服务器;
- 浏览器检查浏览器⾃身的DNS缓存中,是否有域名对应的DNS缓存
- 查看系统的hosts⽂件是否有域名对应的IP地址
- 浏览器发起DNS系统调⽤,向本地配置的⾸选DNS服务器发起域名解析请求(通过UDP协议,向DNS的53端⼝发起请求)
- ⾸先,请求会在运营商DNS服务器(本地服务器)上进⾏请求,若找到对应的条⽬,且没有过期,则解析成功;否则,进⼊5
- 运营商DNS服务器,根据解析请求,迭代查询,⾸先找到根域名服务器IP地址,然后找到根域的DNS地址,发送请求
- 根域服务器收到请求后,根据域名,返回对应的顶级域服务器IP地址,并返回给运营商DNS服务器
- 运营商DNS服务器收到根域名服务器传回来的顶级域名服务器IP地址后,向顶级域名服务器发送请求
- 顶级域名服务器收到请求后,返回该域名对应的权威域名服务器IP地址,并返回给运营商DNS服务器
- 运营商DNS服务器获得权威域名服务器的响应信息后,返回给请求的主机,DNS解析完成。
输入URL到显示的过程
- DNS解析
- TCP连接
- 发送HTTP请求
- 服务器处理请求并返回HTTP报文
- 浏览器解析渲染页面
- 连接结束
web⻚⾯请求
1.1 查找DNS缓存
- 先查找浏览器DNS缓存,看是否存放⽬标⽹络的IP地址;
- 如果不在浏览器缓存,则浏览器将对操纵系统发起系统调⽤,查询操作系统本地缓存;
- 如果不在操作系统本地缓存,则浏览器会查询与之相连的路由器缓存;
- 如果不在路由器缓存,则浏览器会检查ISP【本地通信服务商】缓存;
若以上四步均没有查询到⽬标⽹络的IP地址,则发起DNS查询。
1.2 发起DNS查询
判断DNS服务器和我们的主机是否在同⼀⼦⽹内
- 在同⼀⼦⽹,则采⽤ ARP 地址解析协议对 DNS 服务器进⾏ ARP 查询
- 不在同⼀⼦⽹,则采⽤ ARP 地址解析协议对默认⽹关进⾏查询
若此时还是查询不到 IP 地址,则根据拿到 DNS 服务器或者默认⽹关的 IP 地址,继续进⾏ DNS 请求,使⽤53端⼝先向本地 DNS 服务器发送 UDP 请求包
,此处⼀般使⽤ UDP 协议(如果响应包太⼤,则使⽤ TCP 协议)
没有查询到 IP 地址:
则它会发送⼀个递归查询请求,⼀层⼀层向⾼层DNS服务器查询,直到查询到 IP 地址,则将结果返回
【解释:DNS 是分布式域名服务器,每台服务器只维护⼀部分 IP 地址到⽹络地址的映射,没有任何⼀台服务器能够维持全部的映射关系】。
1.3 封装TCP数据包
拿到 IP 地址后,根据 URL 中的端⼝可知端⼝号【HTTP:80;HTTPS:443】,⼀般先会先尝试建⽴ HTTP 连接;
准备 TCP 数据包:
步骤:
- 将应⽤层传递下来的实际数据,在传输层添加TCP⾸部;
- 将传输层传下来的数据在⽹络层添加IP⾸部;
- 将⽹络层传输下来的数据,在数据链路层添加以太⽹⾸部,并在传输介质中进⾏传输。
1.4 浏览器与⽬标服务器建⽴TCP连接
经过上述DNS和ARP查询流程后,浏览器会收到⽬标服务器的IP和MAC地址,然后经过三次握⼿后建⽴TCP连接;
1、使⽤HTTP协议
浏览器发送请求到服务器,如果使⽤的是HTTP协议,则服务器直接返回结果;
2、使⽤HTTPS协议
如果不是 HTTP 协议,则服务器会返回⼀个以 3 开头的重定向消息,告诉浏览器使⽤的 HTTPS,IP 没变,只是端⼝号变成 443;完成四次挥⼿;重新建⽴ TCP 连接,将端⼝号修改为 443,同时沟通好双⽅的使⽤的认证算法、加密和解密算法,在次过程中也会
检查对⽅的 CA 安全证书,采⽤ SSL 加密技术进⾏传输数据。
1.5 浏览器发送HTTP/HTTPS请求到web服务器
主要使⽤两种请求⽅式:
- 浏览器发送get请求,要求⽬标服务器提供输⼊的⽹⻚;
- 浏览器发送post请求,表示填写的是表单。
1.6 服务器处理请求并发挥⼀个响应
服务器会从浏览器接受请求并将其传递给请求处理程序并响应;
1.7 服务器发回⼀个HTTP响应
⼀般响应包包含:请求的⽹⻚以及状态码,压缩类型,如何缓存的⻚⾯,设置的cookie;
1.8 浏览器显示HTML⻚⾯
- 渲染HTML⻣架;涉及到Ajax技术;
- 检查HTML标记并发送GET请求以获取⽹⻚上的其他元素【图像、CSS样式、JS⽂件等】,该静态⽂件⼀般由
浏览器缓存,再次访问,不⽤᯿新请求; - 最后会看到请求⾊彩斑斓的⽹⻚。
GET和POST的区别
(1)功能:get一般用来从服务器上面获取资源,post一般用来更新服务器上面的资源。
(2)幂等性:get 是幂等的,post 为非幂等的
(3)安全性:get 请求的参数会明文附加在URL之后,而 post 请求提交的数据则被封装到请求体中,相对更安全。
(4)传输数据量的大小:get请求允许发送的数据量比较小,大多数浏览器都会限制请求的url长度在2048个字节,而大多数服务器最多处理64K大小的url;而post请求提交的数据量则是没有大小限制的。
(5)参数的数据类型:GET只接受ASCII字符,而POST没有限制。
(6)GET在浏览器回退时是无害的,而POST会再次提交请求。
(7)get请求可以被缓存,可以被保留在浏览器的历史记录中;post请求不会被缓存,不会被保留在浏览器的历史记录中。
GET⽅法只产⽣⼀个TCP数据包,浏览器会把请求头和请求数据⼀并发送出去,服务器响应200 ok(返回数据)
。POST会产⽣两个TCP数据包,浏览器会先将请求头发送给服务器,待服务器响应100 continue,浏览器再发送请求数据,服务器响应200 ok(返回数据)
。
TCP与UDP的区别
socket
设计模式
单例模式
保证⼀个类仅有⼀个实例,并提供⼀个访问它的全局访问点
⼯⼚模式
Linux
IO复用
各种IO模型的⽐较
1、同步I/O
导致请求进程阻塞,直到I/O操作完成;
四种同步模型的区别在于第⼀阶段等待数据的处理⽅式不同,第⼆阶段均为将数据从内核空间复制到⽤户空间缓冲区期间,进程阻塞于recvfrom调⽤。
2、异步I/O
不导致请求进程阻塞。
3、I/O复⽤函数
多路复⽤接⼝ select/poll/epoll ,内核提供给⽤户态的多路复⽤系统调⽤,进程可以通过⼀个系统调⽤函数从内核
中获取多个事件:
(1)select–>两次遍历+两次拷⻉
- 把已连接的socket放在⼀个⽂件描述符集合,调⽤ select 函数将⽂件描述符集合拷⻉到内核⾥,让内核来检
查是否有⽹络事件产⽣; - 通过遍历,有事件产⽣就把此socket标记为可读/可写,然后再整个拷⻉回⽤户态;
- ⽤户态还需要遍历找到刚刚标记的socket。
(2)poll
动态数组,以链表形式来组织,相⽐于select,没有⽂件描述符个数限制,当然还会受到系统⽂件描述符限制。
(3)epoll(event poll)–>红⿊树
- 在内核⾥使⽤红⿊树来跟踪进程所有待检测的⽂件描述字。
- 调⽤epoll_ctl() 函数,把需要监控的 socket 加⼊内核中的红⿊树⾥:(红⿊树的增删查时间复杂度是O(logn),不需要每次操作都传⼊整个集合,只需要传⼊⼀个待检测的socket,减少了内核和⽤户空间的大量数据拷⻉和内存分配)
- epoll 使⽤事件驱动的机制,内核⾥维护了⼀个链表来记录就绪事件(当某个 socket 有事件发⽣时,通过回调函数,内核会将其加⼊到这个就绪事件列表中)
- 当⽤户调⽤ epoll_wait() 函数时,只会返回有事件发⽣的⽂件描述符的个数,不需要像 select/poll 那样轮询扫描整个 socket 集合,⼤⼤提⾼了检测的效率。
(4)epoll触发模式
- epoll⽀持的事件触发模式:(1)边缘触发ET (2)⽔平触发LT。
- 边缘触发模式ET
当被监控的 Socket 描述符上有可读事件发⽣时,服务器只会从 epoll_wait中苏醒⼀次,即使进程没有调⽤
read 函数从内核读取数据,也依然只苏醒⼀次,因此我们程序要保证⼀次性将内核缓冲区的数据读取完,只
有第⼀次满⾜条件的时候才触发,之后就不会再传递同样的事件了。 - ⽔平触发模式LT
当被监控的 Socket 上有可读事件发⽣时,服务器不断地从 epoll_wait中苏醒,直到内核缓冲区数据被 read
函数读完才结束,⽬的是告诉我们有数据,只要满⾜事件的条件,⽐如内核中有数据需要读,就⼀直不断地把
这个事件传递给⽤户。
(5)select和epoll的区别
- select 和 poll 采⽤轮询的⽅式检查就绪事件,每次都要扫描整个⽂件描述符,复杂度O(N);
- epoll 采⽤回调⽅式检查就绪事件,只会返回有事件发⽣的⽂件描述符的个数,复杂度O(1);
- select 只⼯作在低效的LT模式,epoll 可以在 ET ⾼效模式⼯作;
- epoll 是 Linux 所特有,⽽ select 则应该是 POSIX 所规定,⼀般操作系统均有实现;
- select 单个进程可监视的fd数ᰁ有限,即能监听端⼝的⼤⼩有限,64位是2048;epoll 没有最⼤并发连接的限
制,能打开的 fd 的上限远⼤于2048(1G的内存上能监听约10万个端⼝); - select:内核需要将消息传递到⽤户空间,都需要内核拷⻉动作;epoll通过内核和⽤户空间共享⼀块内存来实
现的。
怎么考虑用不用消息队列
- 系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入 MQ 之前,你不用考虑消息丢失或者说 MQ挂掉等等的情况,但是,引入 MQ 之后你就需要去考虑了!
- 系统复杂性提高: 加入 MQ 之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
- 一致性问题:我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!
TCP 如何保证传输可靠性?
- 应用数据被分割成 TCP 认为最适合发送的数据块。
- TCP 给发送的每一个包进行编号,接收方对数据包进行排序,把有序数据传送给应用层。
- 校验和: TCP将保持它首部和数据的检验和。这是一个端到端的检验和,目的是检测数据在传输过程中的任何变化。如果收到段的检验和有差错,TCP
将丢弃这个报文段和不确认收到此报文段。- TCP 的接收端会丢弃重复的数据。
- 流量控制: TCP 连接的每一方都有固定大小的缓冲空间,TCP
的接收端只允许发送端发送接收端缓冲区能接纳的数据。当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。TCP使用的流量控制协议是可变大小的滑动窗口协议。
(TCP 利用滑动窗口实现流量控制)- 拥塞控制: 当网络拥塞时,减少数据的发送。
- ARQ 协议: 也是为了实现可靠传输的,它的基本原理就是每发完一个分组就停止发送,等待对方确认。在收到确认后再发下一个分组。
- 超时重传: 当 TCP 发出一个段后,它启动一个定时器,等待目的端确认收到这个报文段。如果不能及时收到一个确认,将重发这个报文段。