1、TCP三次握手、四次挥手
-
TCP:
传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。 -
TCP三次握手过程:
tcp三次握手.png
开始客户端处于closed状态,服务端处于listen状态。
第一次握手:客户端向服务端发送SYN报文(即同步标志位SYN=1),并指明客户端的初始化序列号ISN(比如seq=x),此时客户端处于SYN_SEN状态。
第二次握手:服务端收到客户端的SYN报文,会以自己的SYN报文作为应答,并指定自己的初始化序列号ISN(比如seq=y),同时会把客户端的ISN+1作为ack的值,表示自己已经收到了客户端的SYN,此时服务端处于SYN_RCVD状态。
第三次握手:客户端收到服务端的SYN报文之后,会发送应答报文,将服务端的ISN+1作为ack的值,此时客户端处于established状态。
当服务端收到客户端的ACK报文后,服务端也处于established状态,此时连接正式建立。 -
三次握手的作用:
(1) 确认双方的接收和发送能力都是正常的。
(2) 指定自己的初始化序列号,为以后的可靠传输做准备。 -
ISN是固定的吗?
三次握手的一个重要功能就是客户端和服务端交换ISN,以便让对方知道接下来接收数据时如何通过序列号来组装数据。ISN不是固定不变的,攻击者很容易猜出后边的序列号,因此ISN是动态生成的。 -
第三次握手失败会怎样?
当服务端向客户端发送了SYN-ACK包而未收到客户端的确认,服务端会进行首次重传,当等待一段时间还是未收到,会进行第二次重传,当重传次数超过系统规定的最大重传次数,服务端会从半连接队列中删除连接信息。此时如果客户端向服务端发送数据,服务端会返回RST报文。 -
RST报文:
RST(Reset the connection)用于复位因某种原因引起出现的错误连接,也用来拒绝非法数据和请求。 -
半连接队列和全连接队列:
当服务端处于SYN_RCVD状态时,会把连接信息放到半连接队列中。全连接队列用来存放已经完成三次握手的那些连接信息。 -
三次握手中是否可以携带数据?
第一次握手和第二次握手是不可以携带数据的,第三次握手是可以携带数据的。如果第一次握手和第二次握手可以携带数据,则服务端或客户端会花费大量的时间和内存来接收这些报文,从而造成攻击。 -
TCP四次挥手过程:
TCP四次挥手.png
上图以客户端主动关闭连接为例,开始客户端和服务端都处于ESTABLISED状态。
第一次挥手:客户端发送FIN报文,并指定自己的序列号(seq=u),此时客户端处于FIN_WAIT1状态。
第二次挥手:服务端接收到客户端的FIN报文后,会发送ACK报文,且把客户端的的序列号值加1作为ack的值,表明已经收到了客户端的报文,此时服务端处于CLOSE_WAIT状态。而客户端收到服务端的ACK报文后,处于FIN_WAIT2状态。
第三次握手:当服务端也想断开连接,则向客户端发送FIN报文,并制定序列号值,此时服务端处于LAST_ACK 状态。
第四次握手:当客户端收到服务端的FIN报文时,会发送ACK报文,并将服务端的序列号值加1作为ack的值,此时客户端处于TIME_WAITED状态。需要经过一段时间(一般是一个报文来回的时间)客户端才进入CLOSED状态。服务端收到客户端的ACK报文后就会进入CLOSED状态。 -
TIME_WAIT状态:客户端为什么需要等待一段时间才进入CLOSED状态?
确保服务端已经收到了客户端的ACK报文,如果服务端没有收到客户端的确认,服务端会重新发送FIN报文给客户端,如果此时客户端立刻关闭了,则服务端会一直以为客户端没有收到FIN报文。
2、java类加载过程
-
类加载的七个阶段:
类从加载到虚拟机内存到卸载出虚拟机内存,包括加载、连接(验证、准备、解析)、初始化、使用、卸载七个阶段。
类加载过程.png
加载:根据一个类的全限定名(包名+类名)来读取此类的二进制字节流到JVM内部,将字节流代表的静态存储结构转换为方法区的运行时数据结构,转换为一个与目标类型对应的java.lang.class对象。
验证:主要是为了确保class字节流中包含的信息是否符合当前虚拟机规范,不会危害虚拟机自身的安全。包括文件格式验证、元数据验证、字节码验证、符号验证。
准备:为类中的所有静态变量分配内存空间,并设置初值。
解析:将常量池中的符号引用转换成直接引用,即得到类或者字段、方法在内存中的指针或者偏移量,一遍直接调用该方法。
初始化:根据代码逻辑为静态变量赋初值。静态变量的声明和静态代码块是按代码先后顺序执行的。 -
类加载器:
启动类加载器(BootStrapClassLoader):负责加载JDK中的核心类库(java.lang.*等)。
扩展类加载器(ExtClassLoader):负责加载java的扩展类库,默认加载JAVA_HOME/jre/lib/ext/目下的所有jar。
系统类加载器(AppClassLoader):负责加载应用程序classpath目录下的所有jar和class文件。
用户自定义类加载器(UserClassLoader): -
双亲委派机制:
当一个ClassLoader实例需要加载某个类时,会先检查是否已经加载过,如果已经加载了则直接返回,如果没有加载则递归调用父加载器去加载,如果父加载器都不能加载,则尝试自己加载。
好处:
(1) 避免一个类被重复加载
(2) 确保每个类加载器只加载自己范围的类
在JVM中如何唯一确定一个java类?
类路径加类加载器,即使是同一个类被不同的类加载器加载,JVM也会认为是不同的类。 -
如何打破双亲委派模型?
(1) 继承ClassLoader类
(2) 重写loadClass 和 findClass方法。其中loadClass实现了双亲委派机制的逻辑。即先让父加载器加载类,不行在自己加载。 -
类什么时候会被加载?
(1) 实例化对象时
(2) 通过类名访问静态变量或静态方法时
(3) 通过反射访问一个类时 -
类什么时候会被卸载?
(1) 该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。
(2) 加载该类的ClassLoader已经被GC。
(3) 该类的java.lang.Class 对象没有在任何地方被引用,如不能在任何地方通过反射访问该类的方法 。


