计算机组成
cpu
CPU负责计算
PC,(program container)指令寄存器,根据指令地址读取指令和所需数据
registers,寄存器,存在多个,保存PC读取的数据,返回给内存计算结果
ALU,算数逻辑单元,对寄存器中的指令和数据进行计算
cache,缓存。三级(L1,L2,L3)
多核cpu的每个核有自己的L1,L2
多核共享L3
多个CPU共享内存(主存)超线程【四核八线程】
在一个cpu中,存在多个pc和registers。
ALU在进行计算时会再多个线程之间来回切换,但是pc和register中只能保存一个线程的数据,所以在切换时就需要把当前线程的数据保存到内存后,切换到其他线程。当再次切换回来时,从内存中进行现场恢复继续执行。
但是从内存中进行恢复比较慢,所以,在cpu中多个pc和register可以保存多个线程的数据,ALU在计算时可以不用和内存进行IO,提高速度。
缓存行
cpu从内存中读取数据不是一个字节一个字节的读取,是一行一行的读取,叫做缓存行
缓存行大小是64byte。因为这样提高运算效率,不用需要数据就去内存中读取。
缓存行被读取后放到cpu的L1或者L2缓存中。
缓存一致性协议
MESI只是缓存一致性协议的一种。
缓存被读取到L1,L2中后,会存在这样的问题。如果多个线程共享缓存行中的数据,也就是说同一个缓存行,被读取到了多个cpu中。那么这时就会发生数据不一致的情况。(多线程并发问题)
缓存行的状态:
- M:modified,被修改
- E:exclusive,独占
- S:shared,共享
- I:invalid,失效
java中volatile关键字。被volatile修饰的变量,在被修改后,缓存行在当前线程的状态变为modified,并通过总线通知其他线程中缓存行变为invalid,其他线程需要重新从内存中读取。
所以,当两个volatile修饰的属性在同一个缓存行中的时候,当他们被频繁修改时,就会频繁通知对方从内存中重新读取,那么就造成运行效率变慢。
经典验证volatile影响运行效率的程序
因为缓存块的 大小是64byte,一个long型属性是8byte,所以可以通过控制数量的方法将两个volatile变量分开到不同的缓存块中与不分开的情况进行比较。
上述方法叫做缓存行对齐
指令重排序
在不影响执行结果的条件下,将代码进行重新排序执行,来提高执行效率。
内存
内存负责存储需要计算的数据,没有内存只能进行手动输入数据,执行一次计算
CPU + 内存实现了自动计算,是最主要的两部分。
CPU和内存之间需要进行通信,才能完成自动计算。
通信依靠的是总线
计算机网络
OSI7层参考模型
- 应用层
- 表示层
- 会话层
- 传输控制层,规定传输规则,进行几次握手,几次通信,发送几次数据包
- 网络层,网络层规定ip协议,确定数据包怎么发送
- 链路层,链路层实现数据包的发送
- 物理层
参考模型只是参考,实际并不这样设计的,分层的目的是解耦
程序员面向应用层开发应用程序,表示层和会话层也属于应用层的一部分也是开发人员需要解决的。
TCP
TCP是传输控制层的一个协议。面向连接(区别与udp)的可靠的传输协议。
三次握手
为了创建可靠的通信连接,A向B发送syn数据包,B收到后回复一个syn+ack说明已经接收到连接请求。A在接收到回应之后也会发送ack通知B,已经接收到回应。之后A会准备进行通信传输,B收到ack后确定A要开始进行通信了,会开辟端口用于通信。至此通信完全建立。
三次握手当中,前两次都不能携带数据。第三次可以携带数据。,因为B已经做好接受准备了。
B在发送完syn和ack响应之后,会开辟端口号,等待A的ack反馈,如果这是A不发送ack,B又没有设置超时时间,B会一直开辟端口号等待反馈。如果使用大量的肉鸡访问B,容易造成DOS攻击。
为什么两次不行
A发送请求B回应之后,不能确定A是否能够接收到数据。
而tcp要求可靠性,就要保证传输和接受双方发送和接收数据的能力,只有两次B无法确定A是否能够接收到数据。无法建立可靠连接。
TCP 长连接
客户端和服务器建立tcp连接之后,会一直存在,默认情况下如果其中一方网络断开,不会影响另一方的数据传输,也就是客户端断开了连接,服务端也会一直发送数据。是因为tcp是一个可靠的连接,连接建立之后不发起断开请求不会断开。
上述只是默认情况,会引起一个问题,就是其中一方断开后,另一方一直发送数据会占用资源。所以引入了心跳机制和超时机制,心跳机制就是需要检测对方是否存活,每隔一段时间就要发送数据包进行验证。如果长时间没有心跳通信,超过超时限制之后就会从传输队列中踢出,保证不会一直占用资源。
四次挥手
断开连接,需要双方销毁资源。
- A发送fin给B,表示请求断开连接
- B发送fin+ack,表示已经收到
- B发送fin给A,表示同意断开连接
- A发送ack给B,表示收到断开连接请求
- 双方销毁资源。
为什么要四次挥手?为什么三次不行?
因为A在发送断开请求之后,B可能存在没有发送完的数据,需要等待该数据发送完成后才能断开连接。如果B只给一次回应的话,可能会漏发数据。再有B接受到断开请求后要立马给A一个ack应答,表明自己收到了请求,这就导致了B不能等到数据都发送完之后一次性返回。所以中间的两次不能省略。
socket
socket是一个四元组:ip:port+ip:port。为了保证连接的唯一性
端口号最大的端口号数量65535,也可以设置数量
对于服务端B的某个服务有唯一的端口号如80。客户端A最多可以产生【65535】个连接。
而服务端消耗一个端口号用于提供服务。
ip:port+ip:port意味着双方的ip+端口合在一起组成一个四元组,四部分中存在一部分不同都是不同的连接。
如果A已经和B的80建立了65535个连接,此时B又建立了90端口的服务。A还是可以建立65535个连接来连接B的90端口
tcpdump
tcp抓包工具。
tcpdump -nn -i eth0 port 80 //监听eth0的所有跟80端口有关的数据包
-nn 代表显示ip地址
-i 选择网卡
port 端口号
-x 显示包内容
实验:
监听80端口,然后使用 curl www.baidu.com
访问百度。会完整走一次三次握手+四次挥手。
IP
ip是网络层的协议
A类地址:1-126,子网掩码:/8(8个1)
B类地址:128-191,子网掩码:/16
C类地址:192-223,子网掩码:/24
ipaddr是点分字节。使用【.】来划分字节,每个字节8个比特,最大是2的8次方-1,所以取值范围是0-255。
netmask掩码,由连续的0和1组成,不会出现01交叉。进行子网划分
gateway网关,
dns负责域名解析,例如访问www.baidu.com,会解析成百度服务器的ip
路由
计算机通过网络与其他计算机进行网络传输,需要经过路由转发
通信时,使用目标地址与路由中的掩码进行按位与运算。得到的结果与网络目标进行匹配,如果匹配成功,则跳转到指定网关进行传输。
IPv4 路由表
===========================================================================
活动路由:
网络目标 网络掩码 网关 接口 跃点数
0.0.0.0 0.0.0.0 172.20.10.1 172.20.10.5 35
===========================================================================
当前情况下访问任何地址都会与0.0.0.0进行按位与运算得到的结果都是0.0.0.0能够与网络目标匹配到,符合第一条路由。也就是说所有网络传输都会跳到172.20.10.1的网关。发送到网关之后使用同样的方法匹配路由决定目标机器。
链路层
arp协议
广播协议,在局域网中寻找机器时,广播寻找目标ip的mac地址(由广播地址实现广播,广播地址是x.x.x.255),目标ip机器收到广播后发送反馈给广播地址。找到了固定的mac地址才能进行通信。
每个ip本地会存有一个局域网地址与mac的映射表。如果映射表中没有目标ip地址,就需要进行广播寻找。
所以一个数据包想要发送,需要在网络层进行一次封装确定目标IP地址,在链路层再次进行封装确定mac地址。在每一次路由跳转中修改mac地址,一步步的找到目标机器,完成数据包的发送。
mac地址是在局域网中唯一的地址,对应固定的物理网口
IO
strace命令:linux用于追踪每个线程的对内核的系统调用
BIO:blocking IO,阻塞io
每个连接创建一个线程来解决阻塞问题,达到可以接受多个连接的目的。
其问题的本质是,内核的accept(用于接受多个请求)和recv(接受数据)两个方法会阻塞。
想要使用strace检测到bio的调用过程,需要使用jdk1.4版本,后续版本都做了优化。
NIO:nonblocking IO,非阻塞IO
优势是规避了多线程的问题,如线程阻塞,资源抢占,线程调度等等
缺点是