1、非对称加密和对称加密的区别

非对称加密和对称加密在加密和解密过程、加密解密速度、传输的安全性上都有所不同,具体介绍如下:

  • 加密和解密过程不同

对称加密过程和解密过程使用的同一个密钥,加密过程相当于用原文+密钥可以传输出密文,同时解密过程用密文-密钥可以推导出原文。但非对称加密采用了两个密钥,一般使用公钥进行加密,使用私钥进行解密。

  • 加密解密速度不同

对称加密解密的速度比较快,适合数据比较长时的使用。非对称加密和解密花费的时间长、速度相对较慢,只适合对少量数据的使用。

  • 传输的安全性不同

对称加密的过程中无法确保密钥被安全传递,密文在传输过程中是可能被第三方截获的,如果密码本也被第三方截获,则传输的密码信息将被第三方破获,安全性相对较低。

非对称加密算法中私钥是基于不同的算法生成不同的随机数,私钥通过一定的加密算法推导出公钥,但私钥到公钥的推导过程是单向的,也就是说公钥无法反推导出私钥。所以安全性较高。

2、TCP的拥塞控制

答:我们知道TCP通过一个定时器(timer)采样了RTT并计算RTO,但是,如果网络上的延时突然增加,那么,TCP对这个事做出的应对只有重传数据,然而重传会导致网络的负担更重,于是会导致更大的延迟以及更多的丢包,这就导致了恶性循环,最终形成“网络风暴” —— TCP的拥塞控制机制就是用于应对这种情况。
首先需要了解一个概念,为了在发送端调节所要发送的数据量,定义了一个“拥塞窗口”(Congestion Window),在发送数据时,将拥塞窗口的大小与接收端ack的窗口大小做比较,取较小者作为发送数据量的上限。
拥塞控制主要是四个算法:

  • 慢启动:意思是刚刚加入网络的连接,一点一点地提速,不要一上来就把路占满。

连接建好的开始先初始化cwnd = 1,表明可以传一个MSS大小的数据。
每当收到一个ACK,cwnd++; 呈线性上升
每当过了一个RTT,cwnd = cwnd*2; 呈指数让升
阈值ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”

  • 拥塞避免:当拥塞窗口 cwnd 达到一个阈值时,窗口大小不再呈指数上升,而是以线性上升,避免增长过快导致网络拥塞。

每当收到一个ACK,cwnd = cwnd + 1/cwnd
每当过了一个RTT,cwnd = cwnd + 1
拥塞发生:当发生丢包进行数据包重传时,表示网络已经拥塞。分两种情况进行处理:
等到RTO超时,重传数据包
sshthresh = cwnd /2
cwnd 重置为 1

  • 进入慢启动过程

在收到3个duplicate ACK时就开启重传,而不用等到RTO超时
sshthresh = cwnd = cwnd /2
进入快速恢复算法——Fast Recovery

  • 快速恢复:至少收到了3个Duplicated Acks,说明网络也不那么糟糕,可以快速恢复。

cwnd = sshthresh + 3 * MSS (3的意思是确认有3个数据包被收到了)
重传Duplicated ACKs指定的数据包
如果再收到 duplicated Acks,那么cwnd = cwnd +1
如果收到了新的Ack,那么,cwnd = sshthresh ,然后就进入了拥塞避免的算法了。


TCP的四种拥塞控制算法

  • 慢开始
  • 拥塞控制
  • 快重传
  • 快恢复

慢开始:
假设当前发送方拥塞窗口cwnd的值为1,而发送窗口swnd等于拥塞窗口cwnd,因此发送方当前只能发送一个数据报文段(拥塞窗口cwnd的值是几,就能发送几个数据报文段),接收方收到该数据报文段后,给发送方回复一个确认报文段,发送方收到该确认报文后,将拥塞窗口的值变为2,

发送方此时可以连续发送两个数据报文段,接收方收到该数据报文段后,给发送方一次发回2个确认报文段,发送方收到这两个确认报文后,将拥塞窗口的值加2变为4,发送方此时可连续发送4个报文段,接收方收到4个报文段后,给发送方依次回复4个确认报文,发送方收到确认报文后,将拥塞窗口加4,置为8,发送方此时可以连续发送8个数据报文段,接收方收到该8个数据报文段后,给发送方一次发回8个确认报文段,发送方收到这8个确认报文后,将拥塞窗口的值加8变为16,

当前的拥塞窗口cwnd的值已经等于慢开始门限值,之后改用拥塞避免算法。

拥塞避免:
也就是每个传输轮次,拥塞窗口cwnd只能线性加一,而不是像慢开始算法时,每个传输轮次,拥塞窗口cwnd按指数增长。同理,16+1……直至到达24,假设24个报文段在传输过程中丢失4个,接收方只收到20个报文段,给发送方依次回复20个确认报文段,一段时间后,丢失的4个报文段的重传计时器超时了,发送发判断可能出现拥塞,更改cwnd和ssthresh.并重新开始慢开始算法,如图所示:

快速重传:
发送方发送1号数据报文段,接收方收到1号报文段后给发送方发回对1号报文段的确认,在1号报文段到达发送方之前,发送方还可以将发送窗口内的2号数据报文段发送出去,接收方收到2号报文段后给发送方发回对2号报文段的确认,在2号报文段到达发送方之前,发送方还可以将发送窗口内的3号数据报文段发送出去,

假设该报文丢失,发送方便不会发送针对该报文的确认报文给发送方,发送方还可以将发送窗口内的4号数据报文段发送出去,接收方收到后,发现这不是按序到达的报文段,因此给发送方发送针对2号报文段的重复确认,表明我现在希望收到的是3号报文段,但是我没有收到3号报文段,而收到了未按序到达的报文段,发送方还可以将发送窗口中的5号报文段发送出去,接收方收到后,发现这不是按序到达的报文段,因此给发送方发送针对2号报文段的重复确认,表明我现在希望收到的是3号报文段,但是我没有收到3号报文段,而收到了未按序到达的报文段,,发送方还可以将发送窗口内的最后一个数据段即6号数据报文段发送出去,接收方收到后,发现这不是按序到达的报文段,因此给发送方发送针对2号报文段的重复确认,表明我现在希望收到的是3号报文段,但是我没有收到3号报文段,而收到了未按序到达的报文段,

此时,发送方收到了累计3个连续的针对2号报文段的重复确认,立即重传3号报文段,接收方收到后,给发送方发回针对6号报文的确认,表明,序号到6为至的报文都收到了,这样就不会造成发送方对3号报文的超时重传,而是提早收到了重传。

3、jvm里怎样判断父类引用子类相关。

  • 声明为类型A是方便编译器能够编译时检查a是否可以调用test()方法,在实际运行时JVM记录a的实际类型是B;
  • 在JVM中,B有一张方法表(分为多行),每一行的内容是方法名和指向方法实现的指针;如果是继承自A、而没有自己实现的方法,则可以将指针直接指到A的相关的方法实现;
  • 在运行时,找到B的的方法表,顺着test()方法的指针找到方法实现,对a执行就可以了。
  • 至于JVM能够记录a的实际类型是B,则太简单了,单凭因为a = new B()就能知道B才是a的实际类型。JVM可以记录一个指针,使得a指向类B。

4、如果对象不可达,一定会非死不可吗?

不一定。
要正真觉得一个对象死亡,还需要至少两次标记过程。
如果对象在进行根搜索后发现没有与 GC Roots 相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是否有必要执行 finalize() 方法。当对象没有覆盖 finalize()方法,或者 finalize() 方法已经被虚拟机调用过,虚拟机认为这两种情况没有必要调用。
将有必要执行 finalize() 方法的对象放入名为 F-Queue 的队列中,稍后虚拟机调用这些对象的 finalize() 方法,这个时候可以拯救一些对象,将需要拯救的对象与引用链建立关系。稍后 GC 将对 F-Queue 中的对象进行第二次的标记,被拯救的对象会被移除集合中。

5、volatile关键字

可见性:

  可见性是一种复杂的属性,因为可见性中的错误总是会违背我们的直觉。通常,我们无法确保执行读操作的线程能适时地看到其他线程写入的值,有时甚至是根本不可能的事情。为了确保多个线程之间对内存写入操作的可见性,必须使用同步机制。

  可见性,是指线程之间的可见性,一个线程修改的状态对另一个线程是可见的。也就是一个线程修改的结果。另一个线程马上就能看到。比如:用volatile修饰的变量,就会具有可见性。volatile修饰的变量不允许线程内部缓存和重排序,即直接修改内存。所以对其他线程是可见的。但是这里需要注意一个问题,volatile只能让被他修饰内容具有可见性,但不能保证它具有原子性。比如 volatile int a = 0;之后有一个操作 a++;这个变量a具有可见性,但是a++ 依然是一个非原子操作,也就是这个操作同样存在线程安全问题。

  在 Java 中 volatile、synchronized 和 final 实现可见性。

原子性:

  原子是世界上的最小单位,具有不可分割性。比如 a=0;(a非long和double类型) 这个操作是不可分割的,那么我们说这个操作时原子操作。再比如:a++; 这个操作实际是a = a + 1;是可分割的,所以他不是一个原子操作。非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。一个操作是原子操作,那么我们称它具有原子性。java的concurrent包下提供了一些原子类,我们可以通过阅读API来了解这些原子类的用法。比如:AtomicInteger、AtomicLong、AtomicReference等。

  在 Java 中 synchronized 和在 lock、unlock 中操作保证原子性。

有序性:

  Java 语言提供了 volatile 和 synchronized 两个关键字来保证线程之间操作的有序性,volatile 是因为其本身包含“禁止指令重排序”的语义,synchronized 是由“一个变量在同一个时刻只允许一条线程对其进行 lock 操作”这条规则获得的,此规则决定了持有同一个对象锁的两个同步块只能串行执行。

6、 DNS协议

DNS 是一个应用层协议,域名系统 (DNS) 的作用是将人类可读的域名 (如,www.example.com) 转换为机器可读的 IP 地址 (如,192.0.2.44)。DNS 协议建立在 UDP 或 TCP 协议之上,默认使用 53 号端口。客户端默认通过 UDP 协议进行通讯,但是由于广域网中不适合传输过大的 UDP 数据包,因此规定当报文长度超过了 512 字节时,应转换为使用 TCP 协议进行数据传输。
可能会出现如下的两种情况:

  • 客户端认为 UDP 响应包长度可能超过 512 字节,主动使用 TCP 协议;
  • 客户端使用 UDP 协议发送 DNS 请求,服务端发现响应报文超过了 512 字节,在截断的 UDP 响应报文中将 TC 设置为 1 ,以通知客户端该报文已经被截断,客户端收到之后再发起一次 TCP 请求。

 eg :我们熟悉的,www.baidu.com
1. com: 一级域名. 表示这是一个企业域名。同级的还有 “net”(网络提供商), “org”(⾮非盈利组织) 等。
2. baidu: 二级域名,指公司名。
3. www: 只是一种习惯用法。

  • 为什么不用域名来直接进行通信呢?

因为IP地址是固定长度的,IPv4是32位,IPv6是128位,而域名是变长的,不便于计算机处理。
IP地址对于用户来说不方便记忆,但域名便于用户使用,例如www.baidu.com这是百度的域名。
总结一点就是IP地址是面向主机的,而域名则是面向用户的。