计算机基础
操作系统
进程和线程之间的区别
进程:是正在被执行的计算机程序
- 每个进程都会被分配一定的逻辑内存空间,逻辑内存空间就是说,比如说给一个进程分配4G内存空间,只是说这个进程可以使用4G内存,并不代表将4G物理内存分配给该进程,因为不管物理内存有多大,每个进程都分配4G物理内存是肯定不可能的
- 操作系统处于硬件和程序的中间层,在程序内看到的只是各自的[寻址空间](# 寻址),进程间的内存都是互相独立的,否则的话,通过修改指针修指向其他进程的内存空间,就会造成一定的安全性问题,比如说通过这样的方式,就可以看到VX或者网上银行内存,造成信息泄露的风险
- 所有进程是可以共享文件资源和网络资源的,不同的进程是可以打开同一个文件或者都可以去抢同一个网络端口
线程:是操作系统能够运算调度的最小单位,包含在进程之中,依赖进程进行执行,是进程中实际运行的单位
- 每个线程都有各自的调用栈,进行函数调用时,会把所有的参数、返回值和局部变量都压入栈中
- 每个线程还有各自的PC指针,指向将要执行指令的地址,也就是说操作系统真正在运行的是一个一个的线程,进程只是一个容器
- 指令本身是存储内存中的,也就是说数据和程序都存储在同一块内存中,这也就出现了一种缓冲区溢出的漏洞,该漏洞是说,在读取用户输入数据的时候,用户输入的很长,超过了给该数据分配的缓冲区大小,溢出到存储程序那块内存,黑客就可以通过这样的方式植入代码,防止该漏洞的方法就是限制用户输入的长度,不要超过缓冲区的大小
- 每个线程同样也有,线程间独立的内存,[thread local](# ThreadLocal)
进程的其实就是一个容器,将一些相关的东西放在一起,将不同的程序隔离开,所以[大致区别就是](# 线程的生命周期)
- 进程间是无法共享内存,就有一些进程之间交互的方案,比较常见的就是通过TCP/IP端口来实现,还有就是信号量、管道等方案,这就和操作系统的相关性稍微大一点;线程之间是可以共享内存的,所以交互就比较简单
- 进程的创建开销比较大,因为要分配比较大的内存;而线程只需要分配一个栈和程序内存就可以了
存储
操作系统的存储是结构化的从下到上分别是:硬盘、内存、缓存、寄存器;这些存储的访问速度又慢到快,反之也由便宜到贵,所以在相同的价格的情况下,通过这样结构下就能达到最优的性能
寻址
寻址空间
是进程中的指针可取到的地址范围,和物理内存大小、内存的多少无关,32位操作系统的寻址空间是2的32次方,也就是4G内存
在装有8G内存的物理机上运行32位的操作系统,每个进程依然只能使用到4G内存,因为指针大小只有32位,只能访问到4G内存大小,所以现在大多数系统都是64位
使用64位的JVM就可以使用更大的内存,虽然Java本身没有指针的概念,但是在[JVM](# JVM)内部是有自己的寻址逻辑,由于Java的移植性,将32位的Java程序移植到64位[JVM](# JVM)上,只需要重新编译一下就可以
寻址过程
指针地址指向的是,进程间独立的逻辑内存,通过逻辑内存和物理内存之间的映射关系,就可以找到真正的存储位置,但是逻辑内存有可能大于物理内存,所以操作系统就会在硬盘空间上创建一个虚拟内存
如果要使用到的数据在物理内存中就直接取出来,放入寄存器进行计算,不再物理内存上就需要先从虚拟内存中读到物理内存,在进行后续操作
但不是将对应的字节直接放入物理内存,因为这样一个字节一个字节进行比对,开销是比较大的,所以在虚拟内存中有分页的概念,将在虚拟内存中的一个分页读入物理内存,如果物理内存放不下虚拟内存中的分页,就会根据一定的算法,将物理内存的数据交还给虚拟内存
所以在运行良好的一个程序中绝大部分数据都在内存中,但是内存使用过多就会产生很多分页,分页在硬盘上,硬盘是比较慢的,所以程序的性能也会受到影响
死锁
死锁的四个必要条件
互斥、请求又保持、不可剥夺、循环等待
避免死锁
- 尽量使用同步代码块不使用同步方法,这样可以自己指定锁对象
- 避免锁的嵌套,如果非要嵌套,对锁排序,来指定获取锁的顺序,同时尽量降低锁的粒度、达到专锁专用
- 多用并发集合、少用同步集合,加锁时使用Lock的tryLock()方法
必然死锁例子
public static void main(String[] args) {
Object lock1 = new Object();
Object lock2 = new Object();
new Thread(() -> {
synchronized (lock1) {
Thread.sleep(1000);
synchronized (lock2) {/*省略*/}
}
}).start();
new Thread(() -> {
synchronized (lock2) {
Thread.sleep(1000);
synchronized (lock1) {/*省略*/}
}
}).start();
}
计算机网络
网络模型
- 物理层主要定义了物理设备的标准,比如网线、光纤的类型、传输速率等,主要作用就是传输比特流。两台物理机之间互相通信,就是机器A向机器B发送比特流,机器B能收到这些比特流,过程就是将机器码转换为电流强弱,传送到目标机后,再将电流强弱转化为机器码,也就是数模转换和模数转换,物理层拥有的物理连接是不可靠,容易出现丢包,重复包,出错,乱序的情况
- 数据链路层定义了如何将数据格式化来后进行传输,还有纠错功能,来确保数据传输的可靠性,将比特数据组织成帧,交换机工作在数据链路层,对帧进行解码,得到帧中包含的目标信息,将数据发送到正确的接收方,主要协议有:ARP地址转化协议,RARP逆向地址转化协议、PPP点对点通信协议
- 网络层定义了如何将网络地址转化成对应的物理地址,并决定将数据包从发送方路由到接收方,网络层通过综合考虑,发送优先权、网络拥塞程度、服务质量、可选路由花费,选出从节点A到节点B的最佳路径,路由器工作在网络层,因为在网络层中要经过很多节点,所以就有可能遭受中间人的攻击,进行窃取和篡改信息,所以任然是[不安全的连接](# HTTP和HTTPS的区别),主要协议有:IP协议、ICMP协议、RIP协议
- 传输层定义如何进行[流量控制](# 滑动窗口),基于接收方能接收数据的快慢程度,来规定适量的发送速率,将较大的数据包拆分后进行编号,因为以太网无法接收大于1500字节的数据包,通过[UDP/TCP](# TCP和UDP的区别)协议来确保出错重传
- 应用层定义了一个固定的消息头,是为了方便接收方能正确解析发送方的数据,主要协议有:[HTTP协议、HTTPS协议](# HTTP和HTTPS的区别)、FTP协议、SSH协议、[DNS协议](# 浏览器输入URL经历的流程)
TCP和UDP
三次握手
TCP协议提供可靠的连接服务,采用三次握手建立一个连接
- 第一次握手:客户端发送SYN包到服务器,同时进入同步已发送状态(SYN_SEND),等待服务端确认
- 第二次握手:服务端收到客户端SYN包后,必须确认客户端的SYN包,同时自己也发送一个SYN包,也就是SYN+ACK包,然后服务端进入同步已收到状态(SYN_RECV)
- 第三次握手:客户端收到服务端的SYN+ACK包后,向服务器发送ACK确认包后,客户端提前进入已建立连接状态(ESTABLISHED),服务端收到ACK确认包后,也进入已建立连接状态(ESTABLISHED)
三次握手的原因
因为通信的双方都需要,告知对方自己Sequence Number的初始值,该值要作为以后数据通信的序号,来保证应用层不会因为网络上的传输问题而乱序,也就是说TCP使用该序号进行数据拼接
在简单点说,客户端和服务端都要知道的四个信息,自己、对方的发送、接收功能是否正常,就是两张表相同的表,拥有四个字段,在都确认无误后就是建立了连接
同时也避免失效了建立连接请求而引发的错误,如果只有是两次握手则会导致,客户端在第一次发送连接请求,由于网络原因超时了,就需要重新发送连接请求,第二次连接请求比第一次连接请求先到达,就会导致的错误和资源浪费
SYN Flood攻击
在第一次握手时还存在SYN超时隐患,如果服务端接收到了客户端发送的SYN并回复SYN+ACK后,但是客户端已经掉线,不会再向服务器发送ACK确认包,这个时候,服务端会不断进行重试,Linux下是5次重试,从1秒开始每次都翻倍,也就是等待63秒才会断开连接
这就使得服务器可能遭到SYN Flood攻击的风险,该攻击指的是客户端发送一个SYN包,服务器需要等待63秒才会断开连接,攻击者就可以尽快耗尽服务器的SYN连接队列,当SYN连接队列满了之后,导致正常的连接请求不能被处理
Linux下通过SYN Cookie来解决该问题,当SYN连接队列满了之后,TCP会通过源地址端口、目标地址端口、时间戳生成一个特别的Sequence Number进行回发,只有是正常连接就会回发SYN Cookie进行建立连接,在连接队列满了之后依然可以建立连接,从而解决该问题
若建立连接后客户端掉线
当建立连接后,客户端掉线,服务端会向客户端发送保活探测报文,如果服务端没收到响应,在保活期内就会继续发送,直到达到保活探测数时,才确认对方主机不可达,就会断开连接
滑动窗口
TCP的拥塞控制和流量控制,是通过滑动窗口来实现,滑动窗口是为了解决,每次发送数据包后,都需要收到该包的确认消息后,才能继续发送后续包,来解决数据包的有序、可靠交付但吞吐量小的问题 ,滑动窗口是按照顺序将处于滑动窗口中的数据包一起发送,当收到所有确认包后,才会向后滑动,若期间有丢包现象,就将在该丢包之前的所有包进行超时重传
四次挥手
TCP是全双工通信,采用四次挥手来释放连接
- 第一次挥手:客户端发送FIN,用来关闭向服务端的数据传输,客户端进入终止等待状态(FIN_WAIT_1)
- 第二次挥手:服务器端收到FIN后,发送一个ACK给客户端,服务器端进入关闭等待状态(CLOSE_WAIT),客户端接收到ACK后,进入下一个终止等待状态(FIN_WAIT_2),这时服务端任然可以向客户端发送数据
- 第三次挥手:服务器端发送一个FIN,用来关闭向客户端的数据传送,服务器端进入最后确认状态(LAST_ACK)
- 第四次挥手:客户端收到FIN后,客户端进入计时等待状态(TIME_WAIT),然后发送一个ACK给服务端,客户端和服务端在等待2MSL后进入已关闭状态(CLOSED)
客户端最后还要等待2MSL的原因
因为最后一个报文没有确认消息,为了保证客户端发送的确认释放连接请求能到达服务端,如果在这个时间段内,服务端没能收到,就会重新发送一次释放连接请求,来确保当前连接的所有报文都已经过期,由于最后一个报文都过了2MSL,所以全部的报文都已经过期
四次挥手的原因
服务端收到释放连接请求时,只是表示对方不再发送数据,但还能接收数据,而自己也未必将全部数据都发送给对方,所以己方可以选择立即关闭连接,也可以选择在发送一些数据给之后再关闭连接,所以确认和释放连接请求会分开为两次,从而导致多了一次,
再简单点说,因为TCP是全双工的,所以发送方和接收方都需要FIN报文和ACK报文,也就是说发送方和接收方各自需都需要两次挥手,只不过有一方是被动的,所以看上去就是四次挥手
服务器出现大量CLOSE_WAIT状态的原因
当客户端发送FIN报文后,服务端没有发送ACK,就会导致服务器保持大量的ClOSE_WAIT状态,也就是说客户端关闭连接后,程序中没有检查到,导致资源一直被程序占用,前台一直在请求,但返回的是异常,并且服务端却没有收到请求,一般是因为程序中的某些连接没有即使释放,或某些配置不合理,比如[线程池](# 线程池)的线程数不合理
TCP和UDP的区别
TCP是面向连接、可靠的、基于字节流的,传输层通信协议,将应用层的数据分隔成报文段,并发送给目标节点的TCP层,为了保证不丢包,就进行了编号,接收方收到后,会发送ACK确认包,如果发送方没能在合理的往返时延内收到确认包,就会进行超时重传,为了保证数据包在正确性,在收发数据包时,都会进行奇偶校验和的计算
UDP是面向无连接的,不维护连接状态,也就不需要连接状态表,尽最大努力交付,但不保证可靠交付,是面向报文的,不对应用程序的数据进行拆分或合并,支持同时向多个客户端传输相同的消息,消息吞吐量只受到数据生成速率、传输速率、机器性能的限制
- TCP是面向连接的,有三次握手连接过程,所以速度较慢,UDP面向无连接的,速度相对较快,适合消息的多播发布,
- TCP是有确认重传机制,比较可靠,而UDP没有
- TCP通过序列号,来保证报文的顺序交互,UDP不具备有序性
- TCP的报头有20个字节,UDP的报头只有8个字节
HTTP和HTTPS
浏览器输入URL经历的流程
- 首先进行DNS解析,将域名转化为对应的IP地址
- 依次检查本地host文件、本地DNS缓存、TCP/IP参数中的DNS服务器地址,DNS服务器向上级进行请求转发,直到那13台根域名服务器,有递归查询和迭代查询两种方式
- 如果有CDN服务器,那DNS会将最终域名解析权,交给CDN专用DNS服务器,CDN服务器会根据用户IP,算出距离用户最近的CDN节点,返回给用户来提高访问速度
- 浏览器与目标服务器建立TCP连接后,发送HTTP请求
- [服务器处理请求](# SpringMVC请求流程),并返回HTTP响应
- 浏览器接收到响应后,进行页面渲染,并释放TCP连接
GET和POST的区别
- 从HTTP协议层面上看:GET请求,是将请求信息放在URL上,长度可能受到限制;而POST请求,是将请求信息放在请求体内,长度不会受到限制
- 从浏览器层面上看:GET请求内容可以被浏览器缓存,POST请求不能被浏览器缓存
- 从数据库层面上看:一般情况下GET请求只是查询,多个GET请求不会改变数据库中的数据,所以多次GET请求获得的结果也是一样的;而POST请求是做增删改,所以会改变数据库中的数据,导致多次POST请求获得的结果可能不一样
HTTP和HTTPS的区别
HTTP支持客户端/服务端模式,只能由客户端发送请求之后,才能得到服务端响应;请求时只需要传送请求方法和请求资源路径,可以传输任意类型的数据,通过HTTP头的Content-Type字段进行标记,默认情况下一个请求由一个连接处理,请求结束后就断开连接,HTTP是无状态的,需要借助[Cookie或Session](# cookie和session的区别)来实现有状态
HTTPS是需要服务使用公钥,向认证机构申请CA证书,之后服务器再收到客户端请求后,就会先返回该证书,证书是无法伪造和修改的,因为不会被浏览器信任,客户端使用浏览器或操作系统内置认证机构的公钥,来辨别证书真伪,并进行并解密,得到服务端非对称加密公钥,用来加密客户端对称加密的密钥,回发给服务端,之后使用对称加密密钥来进行密文传输,从而提高了加解密的效率,简单的说就是使用第三方来证明你是你
- HTTPS需要申请CA证书,HTTP不需要
- HTTPS是具有SSL加密的传输协议,相对于HTTP明文传输更加安全
- HTTPS默认端口是443,HTTP默认端口是80
cookie和session的区别
因为HTTP是无状态的
cookie是客户端记录状态的解决方案,由服务器通过HTTP响应,回发给客户端的特殊信息,以文本形式存放在客户端,之后客户端再向服务器发送请求时,会连同cookie一并发送,服务器接收到cookie后,进行解析,生成与客户端相对应的内容
session是服务端记录状态的解决方案,处理客户端请求时,首先检查客户端请求中是否包含sessionid,如果没有就创建,有就将该sessionid对应的session查出来并使用,session的实现方式主要有借助cookie和URL回写来实现
cookie数据存放在客户端浏览器上,session数据存放在服务器上,所以session相对安全,但是相对服务器压力更大
常见HTTP状态码
- 1XX:临时响应,已接受,但还需要继续处理,没有响应体
- 2XX:成功
200 OK
:请求已成功202 Accepted
:已接受,但未处理完成206 Partial Content
:服务器成功处理了部分内容,多用于请求部分内容,即断点续传完成
- 3XX:重定向
301 Moved Permanently
:永久移动,URI会变,浏览器会有缓存302 Found
:临时移动,URI不会变,浏览器不会有缓存304 Not Modified
:文件未修改,使用本地缓存文件
- 4XX:客户端请求错误
400 Bad Request
:客户端语法错误401 Unauthorized
:未授权的,请求要求客户身份认证403 Forbidden
:拒绝访问,没有权限404 Not Found
:资源未找到406 Non Acceptable
:无可接收的媒体类型416 Range Not Satisfiable
:请求部分资源内容范围错误
- 5XX:服务器错误
500 Internal Server Error
:服务器内部错误,无法完成请求502 Bad Gateway
:网关或代理服务器错误,无效的请求
Comments NOTHING