- 计算机网络
- HTTP协议
- HTTP1.0和HTTP2.0的区别
- HTTP1.1参数keepalive作用
- HTTP和HTTPs的区别
- Https如何加密?https建立连接的过程?
- HTTP请求有哪些?
- HTTP是无状态协议吗?怎么解决?
- HTTP协议如何保持状态
- HTTP状态码
- 重定向和转发区别
- ARP协议的过程
- 什么是ARP欺骗,如何防范?
- post和get区别
- 浏览器输入一个url后发生些什么
- TCP和UDP区别
- TCP和UDP的头部数据
- TCP三次握手哪次更容易受攻击?
- TCP怎么保证达到的数据都是有序的
- TCP中的滑动窗口
- TCP如何保证可靠传输
- 拥塞控制
- TCP粘包
- DDos攻击是什么?
- DNS过程和DNS劫持
- time_wait状态产生的原因是什么?有什么危害?
- socket编程 TCP/UDP用到的各个接口函数
- Cookie和Session的区别
- Session
- DNS使用的是什么协议?
- CSRF攻击
- TCP三次握手
- 为什么要三次握手?
- 三次握手时客户端发送的最后一个ACK丢失怎么办?
- TCP四次挥手
- 为什么要四次挥手?
- 客户端突然挂掉了怎么办?
- TCP/IP 七层结构 / 四层结构
- select,poll, epoll区别
- 操作系统
- 系统调用分类
- 进程间的调度算法
- 操作系统分配给进程空间是怎样的?
- 操作系统的存储结构
- 操作系统内存管理方式
- 操作系统分页和分段的区别
- 快表和多级页表
- 进程调度方法
- 什么是虚拟内存?
- 页面置换算法
- 线程上下文切换和进程上下文切换的区别
- 线程切换代价为什么这么小
- 动态链接和静态链接
- 系统调用
- 进程,线程,协程的区别
- 进程通信方式
- 线程之间的通信方式
- fork函数具体含义
- 现代计算机多核CPU下,如何保证数据一致性?
- 什么是守护进程?
- 上下文切换
- 系统调用和下上文切换的区别
- select,poll,epoll之间的区别
- NIO,BIO,AIO的区别
- java NIO组件
- 四种常用IO模型
- 消息队列 管道 共享内存的区别
- linux相关命令
- linux软链接和硬链接
- 用户态和内核态的区别
- 操作系统的特权级别
- 死锁条件和解决方式
- 写程序模拟死锁
- 页面置换算法
- 缺页中断的具体原理
- 讲一下LRU算法的具体步骤
计算机网络
HTTP协议
(1) Http是超文本传输协议,用于从万维网服务器传输超文本到本地浏览器的传送协议。位于应用层中,端口是80。使用http协议时,客户端首先与服务端的80端口建立一个TCP连接,然后在这个连接的基础上进行请求和应答,以及数据的交换。
(2) Http有两个常用版本,分别是HTTP1.0和HTTP1.1,主要区别是HTTP1.0中每次请求和应答都会使用一个新的TCP连接,而HTTP1.1运行在一个TCP连接上发送多个命令和应答,因此大幅度减少了TCP连接的建立和断开,提高了效率。
(3) HTTP协议的特点是
① 简单快速,客户端向服务器请求时,只需要传送请求方法和路径,由于HTTP协议简单,使得HTTP服务器的程序规模小,通信速度快。
② 灵活。HTTP允许传输任意类型的数据对象。
③ 无连接。限制每次连接只处理一个请求,然后断开连接。
④ 无状态,指的是对事务处理没有记忆能力,不会保存浏览器传送的数据。
HTTP1.0和HTTP2.0的区别
- (1) 多路复用。多路复用允许单一的 HTTP/2 连接同时发起多重的请求-响应消息。多路复用技术是单连接多资源的方式,减少服务端的连接压力,内存占用少,连接吞吐量更大。
(2)首部压缩。维护一份相同的静态字典,包含常见的头部名称,以及特别常见的头部名称与值的组合。
(3) HTTP2.0支持服务器推送。一个服务器经常知道一个页面需要很多附加资源,在它响应浏览器第一个请求的时候,可以开始推送这些资源。这允许服务端去完全充分地利用一个可能空闲的网络,改善页面加载时间。
HTTP1.1参数keepalive作用
- 在第一次创建连接时,服务器会把这个tcp连接保持一段时间。Keepalive就是最大的保持时间,超过时间就会断开连接。
HTTP和HTTPs的区别
| HTTP | HTTPS |
|---|---|
| 默认端口80 | HTTPS默认使用端口443 |
| 明文传输、数据未加密、安全性差 | 传输过程ssl加密、安全性较好 |
| 响应速度快、消耗资源少 | 响应速度较慢、消耗资源多、需要用到CA证书 |
Https如何加密?https建立连接的过程?
- https使用对称加密和非对称加密结合的方式进行通信。
- https不是应用层的新协议,而是http通信接口使用SSL和TLS来加强加密认证。
- 对称加密:加密和解密都是同一个密钥
- 非对称加密:密钥成对出现,分为公钥和私钥。公钥加密需要私钥解密,私钥加密需要公钥解密。
过程:
- 浏览器使用https的url访问服务器,建立SSL连接。
- 服务器收到SSL连接,发送非对称加密的公钥A返回给浏览器。
- 浏览器生成随机数,作为对称加密的密钥B。
- 浏览器使用公钥A,对自己生成的密钥B进行加密,得到密钥C.
- 浏览器将密钥C发送给服务器。
- 服务器使用私钥D对密钥C进行解密,得到对称加密的密钥B。
- 浏览器和服务器之间可以用密钥B作为对称加密密钥进行通信
HTTP请求有哪些?
| 方法 | 描述 |
|---|---|
| GET | 向特定资源发送请求,查询数据,并返回实体 |
| POST | 向指定资源提交数据进行处理请求,可能会导致新的资源建立、已有资源修改 |
| PUT | 向服务器上传新的内容 |
| HEAD | 类似GET请求,返回的响应中没有具体的内容,用于获取报头 |
| DELETE | 请求服务器删除指定标识的资源 |
| OPTIONS | 可以用来向服务器发送请求来测试服务器的功能性 |
| TRACE | 回显服务器收到的请求,用于测试或诊断 |
| CONNECT | HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器 |
HTTP是无状态协议吗?怎么解决?
- (1) HTTP协议是一种无状态的协议,他对用户的操作没有记忆能力,解决方法有两种,一种是session+cookie,另外一种是jwt.
(2) 当用户首次向服务器发送请求时,服务器会创建Session对象,记录用户状态,同时生成一个JsessionID,并通过响应头的set-cookie向客户端发送要求设置cookie的响应。客户端收到响应后,在本机客户端设置了JsessionID的cookie信息,该cookie的过期时间为浏览器会话结束。接下来客户端每次向服务器发送请求时,请求头都会带上该cookie信息,然后服务器根据请求头的cookie信息获取JsessionID,这样浏览器就有了记忆能力。
(3) 第二种是使用JWT机制,JWT是保存在客户端的信息,广泛应用于单点登录的情况。JWT 的 Cookie 信息存储在客户端,而不是服务端内存中。也就是说,JWT 直接本地进行验证就可以,验证完毕后,这个 Token 就会在 Session 中随请求一起发送到服务器,通过这种方式,可以节省服务器资源,并且 token 可以进行多次验证。
HTTP协议如何保持状态
- (1) 共有4种方法:网址重写,隐藏域,cookie和session.
(2) 网址重写是一种session追踪技术,需要将一个或多个token作为一个查询字符串添加到一个url中.比如分页中的下一页.
(3) 将值放在HTML表单的隐藏域中,当用户提交表单时,隐藏域中的值也传送到服务器.只有当页面包含表单,或者可以在页面中添加表单时,才适合用隐藏域.比如在html页面表达中修改用户相关内容时,要将用户id放在隐藏域中.
(4) Cookie是一种由服务器发送给客户端的片段信息,存储在客户端浏览器的内存中或硬盘上,cookie以键值对的形式记录会话跟踪的内容.
(5) Session用于在服务端记录用户状态,将sesionID写入到响应报文中的set-cookie字段,发送给客户端.下次访问时客户端在请求报文中加入cookie值后发送出去,服务器知道是哪个客户了.保存sessionID的cookie在关闭浏览器后就删除了,不能在多个浏览器中共享.如果浏览器端禁用cookie就要使用url重写来实现session跟踪.
HTTP状态码
- 100:Continue —- 继续。客户端应继续其请求。
200:OK —- 请求成功。一般用于GET与POST请求。
301:Moved Permanently —- 永久重定向。
302:Found —- 暂时重定向。
400:Bad Request —- 客户端请求的语法错误,服务器无法理解。
403:Forbideen —- 服务器理解请求客户端的请求,但是拒绝执行此请求。
404:Not Found —- 服务器无法根据客户端的请求找到资源(网页)。
500:Internal Server Error —- 服务器内部错误,无法完成请求。
502:Bad Gateway —- 作为网关或者代理服务器尝试执行请求时,从远程服务器接收到了无效的响应。
503:Service Unavailable — 服务器由于维护或者负载过重未能应答
504:Gateway Timeout — 网关不能及时从远程服务器获得应答。
重定向和转发区别
- 重定向:地址栏发生变化,是两次请求,可以访问其他服务器的资源。
- 转发:地址栏路径不变,是一次请求,只能访问当前服务器下的资源。
ARP协议的过程
- 主机A运行ARP,在本局域网上广播发送一个ARP请求分组。内容是我的ip是xxx,硬件地址是xx,想要知道ip地址为xxx的硬件地址。
- 假设B的IP地址与A要查询的一致,就收下这个ARP分组,并向A发送响应分组,写入自己的硬件地址。内容是我的ip是xx,硬件地址是xxx。 这里是单播
什么是ARP欺骗,如何防范?
- ARP欺骗有两种,一种是对路由器ARP表的欺骗,另外一种是对内网PC的网关欺骗。
- 第一种ARP欺骗的原理是——截获网关数据。它通知路由器一系列错误的内网MAC地址,并按照一定的频率不断进行,使真实的地址信息无法通过更新保存在路由器中,结果路由器的所有数据只能发送给错误的MAC地址,造成正常PC无法收到信息。第二种ARP欺骗的原理是——伪造网关。它的原理是建立假网关,让被它欺骗的PC向假网关发数据,而不是通过正常的路由器途径上网。在PC看来,就是上不了网了,“网络掉线了”。
post和get区别
- (1) GET提交的数据放在url中,post则放在表单中,GET更加不安全。
(2) GET回退浏览器无害,POST会再次提交请求。(GET方法回退后浏览器再缓存中拿结果,POST每次都会创建新资源)
(3) GET提交的数据大小有限制,因为浏览器对url的长度有限制。POST没有。
(4) GET可以被缓存,POST不可以。
(5) GET只允许ASCII字符,POST没有限制。
(6) GET会保存在浏览器历史记录中,POST不会。
(7) GET产生一个TCP数据包,而POST产生两个TCP数据包。(header->data)
浏览器输入一个url后发生些什么
- (1) DNS解析 ——DNS协议
(2) 建立TCP连接 ——TCP,IP,OSPF,ARP
(3) 发送Http请求 ——HTTP
(4) 服务器处理请求并返回http报文
(5) 浏览器解析渲染页面
(6) 连接结束
TCP和UDP区别
- TCP是面向连接的,传输的是字节流,只能点对点,保证传输可靠性,首部是20个字节
- UDP不是面向连接的,传输的是报文,可以一对多,多对一,多对多,提供尽最大努力的交付,首部是8个字节。
TCP和UDP的头部数据
(1) UDP报文段的头部只有8个字节,由四个字段组成。
① 源端口 目的端口 长度 校验和(2) TCP报文段的头部最小是20个字节。
① 源端口,目的端口,序号,确认号
② 数据偏移,保留,URG,ACK,PSH,RST,SYN,FIN。窗口。
③ 校验和,紧急指针。
TCP三次握手哪次更容易受攻击?
- (1) 在第二阶段服务端返回一个确认的SYN-ACK包时容易遭受攻击,即syn洪水攻击。如果客户机伪造出大量第一次使用的syn同步报文,服务器会依次消耗很多资源来保存客户端的信息,并进行确认,但确认失败需要一定时间。
(2) 若短时间有大量syn同步报文涌向服务端,服务端资源可能被耗尽,就导致正常的客户端得不到响应而失败。这是一种常见的DDOS攻击。
(3) 通过防火墙来限制SYN数据报流量速率。
TCP怎么保证达到的数据都是有序的
- (1) 发送方再每次发送数据时,会给每个数据包分配一个序列号,并在特定时间内等待接收方对序列号的确认。
(2) 发送方将已经发送的数据存储在发送缓存中,如果特定时间内没有收到接收方的确认,则需要重新发送此数据包。若收到确认,就将数据包占用的缓存释放。
(3) 接收方收到数据包后按照序列号将数据包按顺序重组,并传给上层使用。
TCP中的滑动窗口
- (1) 发送方根据接收方的窗口构造出自己的发送窗口。在没有收到接收方的确认情况下,发送方可以将窗口内的数据都发送出去,凡是已经发送出去的数据,在未收到确认之前都必须暂时保留,以便在超时重传时使用。
(2) 接收方可以对按序收到的数据中最高序号给出确认。发送方收到确认后,可以将发送窗口向前移动。若在超时计时器时间到达之后,发送方仍然没有收到确认,就重传这部分数据,并重新设置超时计时器,直到收到B的确认为止。
TCP如何保证可靠传输
- 应用数据分割、对数据包进行编号、校验和、流量控制、拥塞控制、ARP协议、超时重传等措施保证数据的可靠传输;
拥塞控制
- 拥塞控制目的:为了防止过多的数据注入到网络中,避免网络中的路由器、链路过载
拥塞控制过程:TCP发送发将维护一个拥塞窗口的状态变量,该变量随着网络拥塞程度动态变化,通过慢开始、拥塞避免等算法减少网络拥塞的发生。
TCP粘包
(1) TCP粘包指发送方发送的若干包数据达到接收方时粘成了一包,从接收缓冲区来看,后一包数据的头紧接着前一包数据的尾。
(2) 造成TCP粘包的原因:
① TCP默认使用nagle算法,该算法做两件事:只有上一个分组得到确认,才会发送下一个分组。收集多个小分组,在一个确认到来时一起发送。Nagle算法造成了发送方可能会出现粘包问题。
② 接收方将收到的数据保存在接收缓存中,然后应用程序主动从缓存读取收到的分组。如果TCP接收数据包到缓存的数据大于应用程序从缓存中读取数据包的速度,多个包就会被缓存,应用程序就可能读取到多个首尾相接粘到一起的包。(3) 什么时候需要处理粘包现象?
① 如果发送方发送的多组数组本来就是同一块数据的不同部分,不需要处理。
② 若多个分组毫不相干,就需要处理。(4) 如何处理TCP粘包现象?
① 对于发送方造成的粘包问题,可以通过关闭Nagle算法来解决。
② 接收方没有办法处理粘包现象,只能将问题交给应用层来处理。
③ 应用层:循环处理,应用程序从接收缓存中读取分组时,读完一条数据就应该循环读取下一条数据,直到所有数据都被处理完成。- 格式化数据,增加结束标识 2) 在数据之前添加发送长度
DDos攻击是什么?
- (1) 就是利用合理的服务请求,占用大量的服务器资源,使合法的用户无法得到服务器的响应.
(2) 常见方式: SYN Flood, UDP Flood, IP Spoofing.
(3) 常用的应对方式:关闭不必要的服务;限制同时打开的SYN半连接数目;缩短SYN半连接的time out时间;利用防火墙和路由器的访问控制列表限制SYN数据包流量速率等。
DNS过程和DNS劫持
(1) 在一个区中,主DNS服务器从自己的本机数据文件中读取该区的DNS数据信息,而辅助DNS服务器则从主DNS服务器中读取该区的DNS数据信息。当一个辅助DNS服务器启动时,需要与主DNS服务器进行通信,并加载数据信息,这就叫做区域传送。该过程需要使用TCP协议。DNS的域名解析使用了UDP协议。
(2) 根域名服务器,顶级域名服务器,权限域名服务器,本地域名服务器。
(3) DNS解析过程:
- ① 主机发起域名请求后,首先检查本地缓存。(浏览器缓存->操作系统的hosts文件)
- ② 若本地缓存中有,直接返回目标IP地址,否则将域名解析请求发送给本地DNS服务器。
- ③ 若本地DNS服务器中有,直接返回IP地址。若没有,则本地DNS服务器将解析请求发送给根DNS服务器。
- ④ 根DNS服务器会返回给本地DNS服务器一个所查询顶级DNS服务器地址列表。
- ⑤ 本地DNS服务器再向上一步返回的顶级DNS服务器发送请求,顶级域名服务器查询并返回域名所对应的权限域名服务器地址。
- ⑥ 本地DNS服务器再向上一步返回的权威域名服务器发送请求,权威域名服务器会查询存储的域名和IP的映射关系表,将IP连同一个TTL(过期时间)值返回给本地DNS服务器
- ⑦ 本地DNS服务器会将IP和主机名的映射保存起来,保存时间由TTL来控制
- ⑧ 本地DNS服务器把解析的结果返回给用户,用户根据TTL值缓存在本地系统缓存中,域名解析过程结束。
(4) DNS劫持
- ① 一种可能的域名劫持方式即黑客侵入了宽带路由器并对终端用户的本地DNS服务器进行篡改,指向黑客自己伪造的本地DNS服务器,进而通过控制本地DNS服务器的逻辑返回错误的IP信息进行域名劫持。
- ② 另一方面,由于DNS解析主要是基于UDP协议,除了上述攻击行为外,攻击者还可以监听终端用户的域名解析请求,并在本地DNS服务器返回正确结果之前将伪造的DNS解析响应传递给终端用户,进而控制终端用户的域名访问行为。
(5) DNS污染
① 我们知道在接收到域名解析请求时,本地DNS服务器首先会查找缓存,如果缓存命中就会直接返回缓存结果,不再进行递归DNS查询。这时候如果本地DNS服务器针对部分域名的缓存进行更改,比如将缓存结果指向第三方的广告页,就会导致用户的访问请求被引导到这些广告页地址上。
time_wait状态产生的原因是什么?有什么危害?
(1) 主动关闭的一方在发送最后一个ACK之后会进入time_wait的状态,发送方在经过2MSL的时间之后才会回到初始状态。MSL是数据包在网络中的最大生存时间。
(2) 产生原因:
- ① 保证客户端发送的最后一个ACK报文能够到达服务器。假设发送方最后发送的ACK在网络中丢失,由于TCP的重传机制,被动关闭的一方将会重发FIN,在该FIN到达之前,发送方必须维护这条连接状态。也就是说这条TCP连接对应的资源不能被立即释放或重新分配,直到另一方重发的FIN达到之后,client重发ACK后,经过2MSL时间周期没有再收到另一方的FIN之后,该TCP连接才能恢复初始的CLOSED状态。
- ② 为使旧的数据包在网络中因过期而消失。发送方在发送完最后一个ACK报文段后,经过时间2MSL就可以使本连接持续时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新连接中不会出现旧的连接请求报文段。
(3) 危害:
① 在高并发短连接的TCP服务器上,当服务器处理完请求后主动请求关闭连接,这样服务器上会有大量的连接处于TIME_WAIT状态,服务器维护每一个连接需要一个socket,也就是每个连接会占用一个文件描述符,而文件描述符的使用是有上限的,如果持续高并发,会导致一些连接失败。
- ② 短连接表示业务处理+传输数据的时间远远小于time_wait的时间,比如取一个web页面,http短连接1s内处理完业务,在关闭连接之后,这个业务用过的端口会停留在time_wait状态几分钟,在这段时间内,其他HTTP请求是无法占用此端口的。故持续的大量高并发短连接,会使服务器因端口资源不足而拒绝为一部分用户服务。
(4) 如何避免?
- ① 服务器可以设置SO_REUSEADDR套接字选项来通知内核,如果端口忙,但TCP连接位于TIME_WAIT状态时可以重用端口。
socket编程 TCP/UDP用到的各个接口函数
(1) TCP编程的服务器端:
① 创建socket()
② 绑定IP地址,端口等信息到socket上,bind()
③ 开启监听listen()
④ 接收客户端发送的连接,accept()
⑤ 收发数据 send()和recv() 或 read()和write()
⑥ 关闭网络连接
⑦ 关闭监听(2) TCP编程的客户端:
① 创建socket()
② 绑定IP地址,端口等信息到socket上,bind()
③ 设置要连接的对方IP地址和端口
④ 连接服务器 connect()
⑤ 收发数据 send()和recv() 或 read()和write()
⑥ 关闭网络连接
Cookie和Session的区别
- (1) 存储位置不同,cookie的数据信息存放在客户端浏览器上。Session的数据信息存放在服务器上。
(2) 存储容量不同,单个cookie保存的数据<=4KB,一个站点最多保存20个cookie.对于session来说没有上限,但是出于对服务器的性能考虑,session内不要存放过多的东西,并且设置session删除机制。
(3) 存储方式不同,Cookie中只能保存ASCII字符串,如果要存储非ASCII字符串还要对其编码。Session中能够存储任何类型的数据。
(4) 隐私策略不同,cookie存储在浏览器中,对客户端是可见的,session存储在服务器上,对客户端是透明的。
(5) 跨域支持上不同,cookie支持跨域名访问,session不支持跨域名访问。
(6) 生命周期不同,cookie保存在硬盘中,通过设置maxAge属性来设置生命周期,如果是比较大的正整数,那么关闭浏览器,cookie还是存在的。Session的保存在服务器中,设置maxInactiveInterval属性值来确定Session的有效期。并且Session依赖于名为JSESSIONID的Cookie,该Cookie默认的maxAge属性为-1。如果关闭了浏览器,该Session虽然没有从服务器中消亡,但也就失效了。
(7) 浏览器支持上,如果浏览器禁用了cookie,那么cookie是无用的。而session可以通过url地址重写来进行会话跟踪。
Session
(1) session是存储在服务端的用户明细表,它是根据cookie来识别用户的。服务器向浏览器发送了一个名为JESSIONID的cookie,它的值是session的id值。
(2) Session无法跨域,当使用不同浏览器访问的时候,新的浏览器没有携带cookie,故获取不到值。(3) 浏览器禁用了cookie,session还能用吗?
① 解决办法:url地址重写。HttpservletResponse提供了两个url地址重写的方法,它们会自动判断该浏览器是否支持cookie,如果支持的话重写后的地址就不会带有jessionid了。如果不支持,那么重写后的地址会带有jessionid.(4) Session不共享问题解决
① Session是依赖于当前系统的tomcat,不同系统之间的session是不共享的。
② Tomcat集群session全局复制,让集群内每个tomcat的session完全同步,这样会影响集群性能。
③ 根据请求的IP使用一致性哈希算法映射到对应机器上,相同参数的请求一直会访问同一个服务器。如果该服务器宕机,会丢失一部分session数据。
④ 将session数据放在redis中。
DNS使用的是什么协议?
- (1) UDP报文的最大长度为512字节,而TCP允许报文长度超过512字节。当DNS查询超过512字节时,会使用TCP进行发送。
(2) 区域传送时使用TCP。辅域名服务器会定时向主域名服务器进行查询以便了解数据是否有变动。如有变动,则会执行一次区域传送,进行数据同步。由于数据同步传送的数据量比一个请求和应答的数据量多得多,加上TCP是一种可靠的连接,所以使用TCP。
(3) 域名解析时使用UDP协议,客户端向DNS服务器查询域名,一般返回的内容都不超过512字节,使用UDP传输即可,这样DNS服务器负载更低,响应更快。
CSRF攻击
(1) 跨站请求伪造,攻击者盗用了用户的身份,以用户的名义发送恶意请求.需要满足两个步骤:
① 用户登录受信任网站A,并在本地生成cookie.
② 在不登出A的情况下,访问危险网站B.(2) 解决方式:
① 在客户端页面增加伪随机数.
② 验证码,每次用户提交都要在表单中填写验证码.
(3) 不使用cookie进行session的验证,而使用http请求参数来传递session id或token可以抵御csrf攻击.
TCP三次握手
- 客户端发送SYN报文,客户端进入同步已发送状态。
- 服务端收到后发送SYN-ACK报文 ,服务端进入同步已接收状态。
- 客户端收到后,发送ACK报文,客户端进入建立连接状态。
- 服务端收到后进入建立连接状态。
为什么要三次握手?
- 防止已经失效的报文段到达服务端发生错误。比如客户端向服务端发送了SYN报文,但在路上滞留了,然后客户端根据重传机制,又重新发送了SYN报文,双方进行了通信。断开后此刻已经失效的报文段到达服务端,服务端还是会向客户端发送确认报文。如果是两次握手,新的连接就已经建立了。但客户端不会理睬服务端的确认信息,也不会向服务端发送确认报文,但服务端认为新的连接已经建立了,并一直等待客户端的数据,这样服务端的资源就被浪费了。
三次握手时客户端发送的最后一个ACK丢失怎么办?
- 由于Server没有收到ACK确认,因此会重发之前的SYN+ACK(默认重发五次,之后自动关闭连接),Client收到后会重新传ACK给Server。如果重发指定次数后,仍然未收到ACK应答,那么一段时间后,server自动关闭这个连接。如果 Client向服务器发送数据,服务器会以RST包(用于强制关闭TCP连接)响应。
TCP四次挥手
- 客户端发送FIN报文,客户端进入终止等待1状态。
- 服务端收到后发送ACK报文,服务端就进入等待关闭状态。
- 客户端收到后,进入终止等待2状态。
- 服务端发送FIN-ACK报文,服务端进入最后确认状态。
- 客户端收到后,发送ACK报文,进入超时等待状态,等待2MSL的时间。
- 服务端收到后,进入关闭状态。
- 客户端也进入关闭状态。
为什么要四次挥手?
- 为了确保数据能够完全传输。
- 前两次是关闭了客户端到服务端的连接,但服务端还可以向客户端发送数据。
- 后两次才关闭了服务端到客户端的连接。
客户端突然挂掉了怎么办?
在服务器端设置保活计时器,每当服务器收到客户端的消息,就将计时器复位。超时时间通常设置为2小时。若服务器超过2小时没收到客户的信息,他就发送探测报文段。若发送了10个探测报文段,每一个相隔75秒,还没有响应就认为客户端出了故障,因而终止该连接。
TCP/IP 七层结构 / 四层结构
- 物理层 (中继器,集线器)
- 数据链路层 PPP点对点协议 (网卡,网桥,交换机)
- 网络层 IP,ICMP,ARP,RIP,OSPF协议 (路由器)
- 传输层 TCP/UDP
- 会话层 RPC,SSL TLS
- 表示层 GIF JPEG HTML ASCII
- 应用层 FTP,HTTP,SMTP,DNS
select,poll, epoll区别
- select 将用户传入的文件描述符数组即fd数组从用户空间拷贝到内核空间,单个线程所能监视的最大fd个数不能超过1024个。select去遍历这个数组,查询每个fd对应的设备状态,直到某个fd就绪后就返回。
- poll和select本质上没有太大区别,只不过没有最大连接数的限制,因为它是基于链表存储的。
- select和poll的特点是水平触发,如果报告了fd后,没有被处理,那么下次还会报告该fd.
- epoll使用一个文件描述符来管理多个描述符,将用户关心的文件描述符的事件存放到内核的一个事件表中。epoll采用事件的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用事件回调的机制来激活该fd,epoll_wait便可以收到通知。
操作系统
系统调用分类
- 设备管理
- 文件管理
- 进程管理
- 内存管理
进程间的调度算法
- 先来先服务
- 时间片轮转
- 短作业优先
- 高响应比优先
操作系统分配给进程空间是怎样的?
- 栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。
堆区(heap)— 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。
静态区(static)—存放全局变量和静态变量的存储
代码区(text)—存放函数体的二进制代码。
线程共享堆区、静态区
操作系统的存储结构

操作系统内存管理方式
分段管理
- 在段式存储管理中,将程序的地址空间划分为若干段(segment),如代码段,数据段,堆栈段;这样每个进程有一个二维地址空间,相互独立,互不干扰。段式管理的优点是:没有内碎片(因为段大小可变,改变段大小来消除内碎片)。但段换入换出时,会产生外碎片(比如4k的段换5k的段,会产生1k的外碎片)
分页管理
- 在页式存储管理中,将程序的逻辑地址划分为固定大小的页(page),而物理内存划分为同样大小的页框,程序加载时,可以将任意一页放入内存中任意一个页框,这些页框不必连续,从而实现了离散分离。页式存储管理的优点是:没有外碎片(因为页的大小固定),但会产生内碎片(一个页可能填充不满)
段页式管理
- 段⻚式管理机制结合了段式管理和⻚式管理的优点。简单来说段⻚式管理机制就是把主存先分成若⼲ 段,每个段⼜分成若⼲⻚,也就是说 段⻚式管理机制 中段与段之间以及段的内部的都是离散的。
操作系统分页和分段的区别
- (1) 相同点:分页和分段都采用离散分配方式,且都是通过地址映射机构(页表,段表)实现地址变换,但它们的区别主要有以下三点:
(2) 页是信息的物理单位,分页是为了实现离散分配方式,以消减内存的外零头,提高内存的利用率。段是信息的逻辑单位,它含有一组其意义相对完整的信息,比如程序段和数据段,分段的目的是为了更好满足用户的需要。
(3) 页的大小固定且由系统决定,而段的长度不固定,取决于用户所编写的程序。
(4) 分页的地址空间是一维的,程序员只需要用一个记忆符即可表示一个地址;而分段的作业地址空间是二维的,程序员在标识一个地址时,既需给出段名,又需给出段内地址。
快表和多级页表
- 为了解决虚拟地址到物理地址的转换速度,操作系统在页表方案基础上引入了快表来加速虚拟地址到物理地址的转换,可以把快表理解为一种特殊的高速缓存寄存器,其中的内容是页表的一部分或全部内容,作为页表的cache,它的作用与页表相似,但提高了访问速率。由于采用页表做地址转换,读写内存数据时,CPU需要访问两次主存,有了快表,只需要访问一次高速缓存存储器,访问1次主存,这样可以加速查找并提高指令执行速度。
- 引入多级页表的目的是为了避免把全部页表一直放在内存中占用过多空间。
进程调度方法
- (1) 先来先服务调度算法
(2) 时间片轮转调度算法
(3) 短作业优先调度算法
(4) 最短剩余时间优先
(5) 高响应比优先
(6) 优先级调度算法
(7) 多级反馈队列调度算法
什么是虚拟内存?
- 虚拟内存的重要意义是它定义了⼀个连续的虚拟地址空间,并且把内存扩展到硬盘空间通过 虚拟内存 可以让程序可以拥有超过系统物理内存⼤⼩的可⽤内存空间。另外,虚拟内存为每个进程提供了⼀个⼀致的、私有的地址空间,它让每个进程产⽣了⼀种⾃⼰在独享主存的错觉(每个进程拥有⼀⽚连续完整的内存空间)。这样会更有效地管理内存并减少出错。
页面置换算法
- (1) 最佳页面置换算法 选择的被淘汰页面将是以后永不使用的,或者是最长时间内不再访问的页面。无法实现,一般作为衡量其他置换算法的方法。
(2) FIFO页面置换算法 总是淘汰最先进入内存的页面
(3) LRU页面置换算法 选择最近最久未使用的页面淘汰
(4) LFU页面置换算法 该置换算法选择在之前时期使⽤最少的⻚⾯作为淘汰⻚。
线程上下文切换和进程上下文切换的区别
进程切换分为两步:
- 切换页目录以使用新的地址空间
- 切换内核栈和硬件上下文
- 对于linux来说进程和线程最大的区别在于地址空间。对于线程切换只需要做第2步就行,所以进程切换开销大。
线程切换代价为什么这么小
- (1) 线程上下文切换和进程上下文切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。
动态链接和静态链接
- (1) 静态连接(.lib | .a)是在程序编译阶段,将程序所需要的函数库打包到一起,而动态连接(.dll|.so)将库函数的连接载入推迟到程序运行时,根据需要进行动态链接。
系统调用
- (1) 进程在操作系统上的运行分为两个级别,用户态的进程可以直接读取用户程序的数据,系统态运行的程序可以访问计算机的任何资源,不受限制。
(2) 在用户程序中,凡是与系统级别的资源有关的操作都必须通过系统调用方式向操作系统提出服务请求,由OS来完成。
(3) 系统调用的功能大致分为设备管理、文件管理、进程控制和内存管理。
进程,线程,协程的区别
- (1) 进程是程序的一次执行过程,是系统执行程序的基本单位。一个进程可以产生多个线程,多个线程共享进程的内存和部分资源,但拥有自己的栈和程序计数器,线程之间的切换成本远远小于进程。
(2) 协程是用户态的轻量级的线程,协程的调度完全由用户控制,一个线程可以有多个协程。
进程通信方式
- 管道 数据只能单向流动,而且只能在父子进程之间使用。
- 信号量 是一个计数器,用来控制多个进程对共享资源的访问。
- 消息队列 消息链表,可以指定消息的类型。
- 共享内存
- 套接字
线程之间的通信方式
- 锁机制 包括互斥锁,条件变量、读写锁。
- wait/notify
- volatile
- countdownLatch , cyclicBarrier
- 信号量机制
fork函数具体含义
- (1) Fork函数成功调用一次返回两个值,子进程返回0,父进程返回子进程id,出错则返回-1。
(2) Fork函数调用成功后,两个进程都将执行fork()函数之后的下一条指令。
(3) 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。
现代计算机多核CPU下,如何保证数据一致性?
(1) 缓存一致性协议MESI。
① 缓存行是缓存存储数据的单元。有MESI四种状态。
② M(modified)该缓存行只存在于该CPU的缓存中,并且是被修改过的,与主存数据不一致。该缓存行中的数据需要在未来的某个时间点被写回主存,其他处理器不能再缓存这个块,写回主存后,该缓存行变为独享状态。
③ E(exclusive)该缓存行只被缓存在该CPU的缓存中,它是未被修改过的,与主存数据一致。该状态可以在任何时刻当有其它CPU读取该内存时变成共享状态(shared)。同样地,当CPU修改该缓存行中内容时,该状态可以变成Modified状态。
④ S(shared) 该缓存行可能被多个CPU缓存,且各个缓存中的数据与主存数据一致。当有一个CPU修改该缓存行,其他CPU中该缓存行可以作废。
⑤ I(invalid)该缓存行中的数据无效。(2) 缓存行是缓存与内存数据交换的最小单位,由状态、地址和数据三个部分组成。状态是MESI,地址是缓存行中映射的内存地址,数据是从内存中读取的数据。
(3) 存在的问题:
① 由于缓存中处于M状态的数据不会立即更新到主存,就会导致它和其他缓存中相同地址的数据会出现短暂不一致的情况。在高并发的情况下,一个线程改变了这个变量的值,另一个线程不会马上知道,造成了数据不一致问题。
什么是守护进程?
- (1) 是linux后台服务进程,是一个生存期较长的进程,通常独立于控制终端并周期性地执行某种任务或等待处理某些发生的事件。
(2) 守护进程程序通常通过如下方法使自己成为守护进程:对一个子进程调用fork,然后使其父进程立即终止,使得这个子进程能在init下运行。这种方法通常被称为“脱壳”。
(3) 系统通常在启动时一同起动守护进程。守护进程为对网络请求,硬件活动等进行响应,或其他通过某些任务对其他应用程序的请求进行回应提供支持。
(4) 守护进程的名称通常以d结尾。
上下文切换
- 多线程编程中一般线程的个数都大于CPU个数,而一个CPU在任意时刻只能被一个线程使用,为了让这些线程都能得到有效执行,CPU采取的策略是为每个线程分配时间片并轮转的形式。当一个线程的时间片用完的时候就会重新处于就绪状态给其他线程使用,这个过程就属于一次上下文切换。
- 任务从保存到再加载的过程就是一次上下文切换。
系统调用和下上文切换的区别
- (1) 系统调用引发的是特权模式切换,指从用户态切换到内核态。只需要在寄存器上下文进行切换,所以耗时相对进程上下文切换更低。
(2) 进程切换只能发生在内核态,进程的上下文切换不仅包括虚拟内存、栈、全局变量等用户空间资源,还包括了内核态堆栈,寄存器等内核空间状态。
(3) 线程上下文切换,两个不同进程的线程上下文切换时,此时的切换构成和进程上下文切换一样。两个线程处于同一进程时,切换只需要切换栈、寄存器等少部分资源。
select,poll,epoll之间的区别
- (1) select,poll,epoll都是IO多路复用的机制。I/O多路复用就通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的。
(2) select调用时,每次select调用时都需要从用户空间向内核空间复制fd数组,数组大小有限制,因为单个进程所能监视的fd数量存在最大限制,通常是1024。调用select后进程会阻塞,直到有某个fd就绪就返回。Select函数返回后,需要遍历fd数组来找到就绪的fd,时间复杂度是0(n).
(3) Poll本质上和select没有区别,但poll没有最大链接数的限制,因为它是基于链表来存储的。时间复杂度是0(n).
(4) epoll相对于select和poll来说,没有描述符限制,epoll使用一个文件描述符来管理多个描述符。将用户关心的文件描述符存放到内核的一个事件表中,这样在用户空间和内核空间只需要复制一次。epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd,epoll_wait便可以收到通知。时间复杂度为O(1)。
NIO,BIO,AIO的区别

(1) BIO同步阻塞式IO,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然可以通过线程池机制改善。 BIO模式下,数据的读取和写入必须阻塞在一个线程内等待其完成,在活动连接数不是特别高的情况下适用。

- (2) NIO同步非阻塞IO,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。 虽然NIO在网络操作中提供了非阻塞的方法,但NIO的IO行为还是同步的。对于NIO来说,业务线程是在IO操作准备好后,得到通知,接着由这个线程自行进行IO操作,IO操作本身是同步的。
- (3) AIO(NIO.2):异步非阻塞式IO,服务器实现模式为一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。 AIO是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会阻塞在那里,当后台处理完成,OS会通知相应的线程进行后续操作。
- (4) NIO和BIO的最大区别是多路复用器,它可以监听来自多个客户端的IO事件。
java NIO组件
- 三大部分: channel(通道), buffer(缓冲区), selector(选择器)。传统IO是基于字节流和字符流进行操作,而NIO是基于Channel和buffer进行操作,数据总是从通道读取到缓冲区中,或从缓冲区写入通道。selector用于监听多个通道的时间,因此单个线程可以监听多个数据通道。
- Buffer
Buffer(缓冲区)是一个用于存储特定基本类型数据的容器。除了boolean外,其余每种基本类型都有一个对应的buffer类。Buffer类的子类有ByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer 。 - Channel
Channel(通道)表示到实体,如硬件设备、文件、网络套接字或可以执行一个或多个不同 I/O 操作(如读取或写入)的程序组件的开放的连接。Channel接口的常用实现类有FileChannel(对应文件IO)、DatagramChannel(对应UDP)、SocketChannel和ServerSocketChannel(对应TCP的客户端和服务器端)。Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。(可以理解为socket) - Selector
Selector(选择器)用于监听多个通道的事件(比如:连接打开,数据到达)。因此,单个的线程可以监听多个数据通道。即用选择器,借助单一线程,就可对数量庞大的活动I/O通道实施监控和维护。
四种常用IO模型
- (1) 同步阻塞IO(BIO)
① 进程发起I/O调用,内核拷贝数据期间进程会因为等待数据拷贝会挂起,把cpu时间片让出去,此时叫做I/O阻塞,I/O完成,进程会被唤醒。
(2) 同步非阻塞IO(NIO)
① 进程的IO请求可以立即返回,可能是一个状态码,说明这个命令不能立即满足,但进程为了拿到数据,需要不断轮询,消耗CPU。一旦数据准备好,进程可以再次发送IO请求。
(3) IO多路复用
① 单个进程可以发起多个IO请求。统一使用一个select进行发起调用,内核内存获取到数据后通知调用方,select将内核空间的数据拷贝到用户空间。
(4) 信号驱动IO
① 水平触发驱动:内核通知进程读取数据,如果没有读取会不断通知进程。边缘触发驱动:内核只通知一次进程读取数据,进程在超时前可以读取数据。
(5) 异步IO(AIO)
① 进程发起IO请求,内核马上返回消息,进程继续其他操作,内核通知读取数据信号,进程处理数据。
消息队列 管道 共享内存的区别
(1) 管道允许在进程之间按照先进先出的方式传送数据,一端进程负责写,另外一端进程负责读。当一端进程正在对管道进行操作时,另外一端的进程只能等待。当管道为空时,读的进程阻塞,管道满时,写的进程阻塞。
(2) 消息队列是消息的链表,是一系列保存在内核中消息的列表。用户进程既可以向消息队列中添加消息,也可以向消息队列读取消息。与管道相比,它的优势是对每个消息指定特定的消息类型,接收的时候可以根据自定义条件接收特定类型的消息。
(3) 共享内存允许两个或多个进程共享一个给定的存储区,这段区域可以被两个或两个以上的进程映射至自身的地址空间中。当一个进程改变了这块地址中的内容的时候,其它进程都会察觉到这个更改。共享内存通信方式效率高,因为进程可以直接读写内存,而不需要任何数据拷贝。缺点:没有同步机制,无法解决多个进程同时读写造成的问题。可以结合管道来使用,规定读写的进程。
(4) 消息队列和管道都需要拷贝数据,过程如下:
① 服务器得到输入
② 通过管道、消息队列写入数据,通常需要从进程拷贝到内核。
③ 客户从内核拷贝到进程。
④ 然后再从进程中拷贝到输出文件。
linux相关命令
(1) 基础命令
① ls 列出当前目录 pwd 打印当前目录的完整路径名
② touch创建文件 cat查看文件 mkdir 创建目录 cd切换目录 rm 删除文件 mv移动 cp拷贝 echo打印变量
③ Head 显示文件前几行,默认为10 tail 从尾部展示文本,一般用来查看日志 more流式读取,支持翻页 nl计算文件中行号
④ wc -l 统计行数 which搜索系统命令的位置 whereis 搜索程序名
⑤ ps -a 查看所有进程 ps -ef 查看进程的环境变量和程序间的关系 kill杀死进程(2) 进阶命令
① find 路径 -name “x.log”查找文件 grep 搜索文件中匹配的内容
② tar -cvf 打包 tar -xvf 解压缩 tar -czvf压缩 tar -xzvf 解压 (-c 建立新的压缩文件 -v 显示操作过程 -f 指定压缩文件 -x从压缩文件中提取文件 -z支持gzip解压文件)
③ du -sh 显示当前目录下每个目录大小 df -h 显示磁盘使用情况
④ ping 将数据包发送给网络主机 netstat -a 查看所有端口使用情况 hostname -i 查看主机的ip地址 wget下载文件
⑤ free显示内存使用情况 vmstat 显示虚拟内存情况 top提供正在运行的系统的动态实时视图。
linux软链接和硬链接
- 硬链接是指通过索引节点来进行链接。inode结点是文件或者目录在一个文件系统中的唯一标识
- 软连接是一个普通文件,文件中存放的内容是另外一个文件的路径名。但若被指向的原文件被删除,则相关软连接就变成了死链接。
用户态和内核态的区别
- 用户态和内核态是操作系统的两种运行级别,两者最大的区别就是特权级不同。用户态拥有最低的特权级,内核态拥有较高的特权级。运行在用户态的程序不能直接访问操作系统内核数据结构和程序。内核态和用户态之间的转换方式主要包括:系统调用,异常和中断。
操作系统的特权级别
- 在linux系统中特权级别分为0,1,2,3一共四个界别,0最大 ,3最小。一般内核代码运行在0特权级,驱动 ,虚拟机等运行在1,2特权级,而我们自己写的程序一般运行在3特权级,也就是最低级别。
死锁条件和解决方式
互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源;
请求与保持条件:进程获得一定的资源后,又对其他资源发出请求,但是该资源可能被其他进程占有,此时请求阻塞,但该进程不会释放自己已经占有的资源
非剥夺条件:进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用后自己释放
循环等待条件:系统中若干进程组成环路,环路中每个进程都在等待相邻进程占用的资源解决方法:破坏死锁的任意一条件
资源一次性分配,从而剥夺请求和保持条件
可剥夺资源:即当进程新的资源未得到满足时,释放已占有的资源,从而破坏不可剥夺的条件
资源有序分配法:系统给每类资源赋予一个序号,每个进程按编号递增的请求资源,释放则相反,从而破坏环路等待的条件
银行家算法,预防死锁。如果检测到给进程分配资源会让系统陷入不安全状态就不予分配。
写程序模拟死锁
class Resource {//申请两个资源public void getAB(String A,String B) throws InterruptedException {synchronized (A){ //先抢占一个资源Thread.sleep(1000);//然后休眠一会System.out.println(Thread.currentThread().getName()+"get"+A);synchronized (B){//再去抢占另外一个资源System.out.println(Thread.currentThread().getName()+"get"+B);}}}}public class DeadLock {public static void main(String[] args) {Resource resource = new Resource();String A = new String();String B = new String();//线程1 A->Bnew Thread(()->{try {resource.getAB(A,B);} catch (InterruptedException e) {e.printStackTrace();}},"1").start();//线程2 B->Anew Thread(()->{try {resource.getAB(B,A);} catch (InterruptedException e) {e.printStackTrace();}},"2").start();}}
排查死锁
- jps -l 查看当前运行的java线程
- jstack 进程号 (可以看出死锁)
解决办法:
- 对资源进行编号,让线程按顺序申请资源即可。
页面置换算法
- 最佳页面置换算法
- FIFO页面置换算法,总是淘汰最先进入内存的页面。
- LRU页面置换算法,选择最近最久未使用的页面淘汰。
- LFU页面置换算法,选择在之前时期使用最少的页面作为淘汰页。
缺页中断的具体原理
- 保留CPU现场,从外存找到缺页,判断内存是否满了,若是则选择一页换出。判断该页是否被修改,若是则先写回外存。若没有被修改,就使用os命令从外存找到缺页,启动IO硬件,将一页从外存换入内存,修改页表和快表,地址变换结束。
讲一下LRU算法的具体步骤
- LRU算法选择的是最近最久未使用的页面予以淘汰。
- 使用双向链表来存储节点,hash表记录节点的位置。
- 双向链表的头部是最近使用的节点,尾部是最久未使用的节点。
get操作
- get先判断节点是否存在,不存在返回-1
- 否则查询在map中查询到该节点,删除该节点,并插入到头部。
put操作:
- 判断键值是否存在,若不存在则新建一个节点,将其插入到双向链表头部,并在map中添加该节点。
- 若链表长度大于规定长度就删除尾部的节点,并删除map中对应的节点。
- 否则查询到该键值在双向链表中的位置,删除该节点,并插入到头部。
