当年,兔子学姐靠这个面试小抄拿了个22k

Posted 兔老大RabbitMQ

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了当年,兔子学姐靠这个面试小抄拿了个22k相关的知识,希望对你有一定的参考价值。

本文顺序是操作系统(jvm)、网络、数据库(mysql/redis),都是当时兔子的学姐准备面试的时候总结的,学生面试基本不会跑出这个范围,懂行的应该能看出来。

学姐原话:因为我本身的知识是A集合,我觉得一次记不住,需要反复看的,我就写了下来B集合。这些并不一定是所有,特别简单的或者特别生僻的A-B都没写。

所以按我的理解,那些,特别特别基础的,不用学姐说,自己也应该会,然后再看这个文章。

目录

生产消费读者写者

进程vs线程

线程生命周期

进程间通信方式

线程间通信方式

进程调度算法

死锁

页面置换算法

磁盘调度算法

jvmjvmjvmjvm区域

判断对象死亡?引用计数 vs 可达性分析

如何回收对象?垃圾收集算法

垃圾收集器

分配回收策略(老年代新生代)

GC调优

JVM常用参数

Cookie session

网络分层

握手挥手

UDP想可靠

网络访问过程

为什么tcp可靠?

UDP可靠

HTTP and HTTPS

HTTP方法及相互区别

状态码

http结构

Tcp结构

Socket

redisredisredis数据结构

对象

跳表

HyperLogLog

单线程

持久化

Redis和数据库双写一致性

缓存击穿雪崩穿透

解决Redis并发竞争Key问题

Redis缓存策略

哨兵

解决会话

sqlsqlsqlsqllsqlslqslqslq数据类型

mysql特点

存储引擎

增删改

范式

索引优缺点和使用原则

索引分类

索引区别

事务特性:ACID

并发错误

隔离级别

并发控制技术(锁)

死锁

分布式事务

SQL语句性能优化

索引的优化

分库分表

Kafka

Es


生产消费读者写者

读者写者:

多读者/多写者互斥/多读者互斥

消费者生产者:全互斥

生产者:p(empty),p(mutex),v(mutex),v(full)

消费者:p(full),p(mutex)v(mutex)v(empty)

进程vs线程

进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。

线程是程序执行时的最小单位,是CPU调度和分派的基本单位。

线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。

线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。

线程生命周期

(五个状态):新建、就绪、运行、阻塞、死亡

新建状态:线程对象已经创建,还没有在其上调用start()方法

就绪状态:当线程调用start方法,但调度程序还没有把它选定为运行线程时线程

运行状态:线程调度程序从可运行池中选择一个线程作为当前线程时线程所处的状态。(是线程进入运行状态的唯一方式)

阻塞(等待/睡眠)状态:线程仍旧是活的,但是当前没有条件运行。当某件事件出现,他可能返回到可运行状态

死亡状态:当线程的run()方法完成时就认为它死去。线程一旦死亡,就不能复生。 一个死去的线程上调用start()方法,会抛出java.lang.IllegalThreadStateException异常

进程间通信方式

  1. 匿名管道:管道的实质是一个缓冲区,该缓冲区是一个循环队列,进程以先进先出的方式从缓冲区存取数据,管道一端的进程顺序的将数据写入缓冲区,另一端的进程则顺序的读出数据。管道的局限性体现在:只支持单向数据流、由于管道没有名字,只能用于有亲缘关系(共同祖先)的进程间通信、缓冲区有限,效率不高
  2. 有名管道:有名管道不同于匿名管道之处在于它提供了一个路径名与之关联,即使与有名管道的创建进程不存在亲缘关系的进程,只要可以访问该路径,就能够彼此通过有名管道相互通信。
  3. 消息队列:消息队列是存放在内核中的消息链表,每个消息队列由消息队列标识符表示。与管道(无名管道:只存在于内存中的文件;命名管道:存在于实际的磁盘介质或者文件系统)不同的是消息队列存放在内核中,只有在内核重启(即操作系统重启)或者显示地删除一个消息队列时,该消息队列才会被真正的删除。
  4. 信号量:信号量是一个计数器,用于多进程对共享数据的访问,信号量的意图在于进程间同步。
  1. 创建信号量:指定初始值,对于二值信号量通常是1。(2)等待信号量:测试信号量的值,如果小于0就阻塞。也称P操作。(3)挂出信号量:信号量值加1,称V操作。

 

为了正确地实现信号量,信号量值的测试及减1操作应当是原子操作。为此,信号量通常是在内核中实现的。Linux环境中,有三种类型:Posix(可移植性操作系统接口)有名信号量(使用Posix IPC名字标识)、Posix基于内存的信号量(存放在共享内存区中)、System V信号量(在内核中维护)。这三种信号量都可用于进程间或线程间的同步。

 

  1. 套接字:是一种通信机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。

(套接字位于传输层与应用层之间)

套接字是支持TCP/IP网络通信的基本操作单元,可以看做主机间进程进行双向通信的端点

 套节字通信基本过程

线程间通信方式

1.锁机制:包括互斥锁(对应于JAVA中的Synchronized)、条件变量(对应于JAVA中的volatile)

*互斥锁提供了以排他方式防止数据结构被并发修改的方法。

*条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

2.信号机制:包括无名线程信号量和命名线程信号量

JAVA中线程通信的具体方式有:1.Volatile和Synchronized 2.wait()和notify()机制 3.管道输入/输出流:PipedReader, PipedWriter 4.Thread.join() 5.TheadLocal类:线程变量,用于线程内部共享数据。以ThreadLocal对象为键,任意对象为值的存储结构 ThreadLocal<String> tl = new ThreadLocal<>();

进程调度算法

先来先服务(FCFS)最简单调度算法。按照进入后备队列的先后次序来加入就绪队列等待执行。是非抢占式,易于实现,效率不高,利于长作业(CPU繁忙)不利于短作业(I/O繁忙)

短作业优先(Short Job First)是非抢占式的,具有很好性能,降低平均等待时间,提高吞吐量。不利于长作业,可能一直处于等待出现饥饿;未考虑作业紧迫程度,不能用于实时系统。

高响应比优先调度算法(Highest Reponse Ratio First, HRRF)(响应比高意味着等待时间长而服务时间短,优先处理)响应比 = (等待 + 服务) / 服务时间 = 等待 / 服务时间 + 1

时间片轮转:用于分时系统的进程调度,抢占式。

基本思想:将CPU时间分为若干时间片(q),进程按到达顺序排列。每次调度队首,执行1个时间片后,该进程移至队尾。能在给定时间响应所有用户请求,达到分时系统的目的。

其性能主要取决于时间片q的大小,q太大,则所有的进程在1个时间片完成;太小则进程频繁切换,系统开销大。

多级反馈队列调度算法:将时间片轮转与优先级调度相结合,把进程按优先级分成不同的队列,先按优先级调度,优先级相同的,按时间片轮转。优点是兼顾长短作业,有较好的响应时间,可行性强,适用于各种作业环境。

死锁

什么是死锁?

当两个以上的运算单元,双方都在等待对方停止运行,以获取系统资源,但是没有一方提前退出时,就称为死锁。

必要条件

禁止抢占 - 资源不能被强制从一个进程中退出

持有和等待 - 一个进程可以在等待时持有系统资源

互斥 – 某个资源在一段时间内只能由一个进程占有

循环等待 - 一系列进程互相持有其他进程所需要的资源,银行家算法-破环循环等待条件,合理分配系统资源

死锁的应对方法

1. 最简单、最常用方法是重新启动,不过代价很大,意味着之前所有进程计算都将付之东流

2. 撤消进程,剥夺资源。终止参与死锁的进程,收回它们占有的资源,从而解除死锁。

分两种情况:一次性剥夺全部资源;或逐步撤消参与死锁的进程,选择逐步撤消目的是撤消代价最小的进程,比如按进程优先级确定代价;考虑进程运行代价和此进程相关作业代价等;

3. 进程回退策略,即让参与死锁的进程回退到没有发生死锁前某一点处。操作起来系统开销大,要有堆栈这样的机构记录进程的每一步变化,以便今后的回退,有时这是无法做到的。

页面置换算法

最佳置换算法(OPT)

最佳(OPT)置换算法所选择的被淘汰页面将是以后永不使用的,或者是在最长时间内不再被访问的页面,这样可以保证获得最低的缺页率。但由于人们目前无法预知进程在内存页面中哪个是未来最长时间内不再被访问的,因而该算法无法实现。

先进先出置换算法(FIFO)

最简单的页面置换算法是先入先出(FIFO)法。这种算法的实质是,总是选择在主存中停留时间最长(即最老)的一页置换,即先进入内存的页,先退出内存。

最近最久未使用(LRU)算法

它的实质是,当需要置换一页时,选择在最近一段时间里最久没有使用过的页面予以置换。

 

 

磁盘调度算法

1.FIFO:先来先服务算法;(依次处理)

2.SSTF: 最短寻道时间算法;(距离当前磁道最近的有限处理)

3.SCAN:电梯调度算法;(这样命名很形象,先按一个方向,扫描的过程依次访问要求服务的队列,当扫描到最里层的一个服务序列时就反向扫描)

4.CSCAN: 循环扫描算法(从最里面一个磁道访问完之后,立即返回最外层,也称单向扫描调度算法)

5.FSCAN:分步电梯调度算法(分两个队列)

 

jvmjvmjvmjvm区域

线程私有的:程序计数器、(虚拟机栈、本地方法栈)

线程共享的:堆、方法区、直接内存 (非运行时数据区的一部分)

程序计数器是一块较小的内存空间,是当前线程执行字节码的行号指示。

工作时通过改变这个计数器的值来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等功能都需要依赖这个计数器来完成。为了线程切换后能恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器。

作用:

通过改变程序计数器来依次读取指令实现流程控制,如:顺序执行、选择、循环、异常处理。

多线程:记录当前线程执行的位置,线程被切换回来时能够知道该线程上次运行到哪儿了。

虚拟机栈(Java 内存可以粗糙的区分为堆内存(Heap)和栈内存 (Stack))

存放基本数据类型(boolean、byte、char、short、int、float、long、double)和对象引用

会出现两种异常:StackOverFlowError 和 OutOfMemoryError。

StackOverFlowError:不动态拓展, 线程请求栈的深度超过当前虚拟机栈的最大深度

OutOfMemoryError: 动态扩展,且内存用完了,无法扩展

堆:唯一目的就是存放对象实例,几乎所有实例和数组都在这里。

方法区(永久代):存储已加载的类信息、常量、静态变量、即时编译器编译后的代码等。

《Java 虚拟机规范》规定了有方法区和作用,并没实现。(像接口),在不同的 JVM 上方法区的实现肯定是不同的了。 永久代是 HotSpot 虚拟机对方法区的一种实现方式。(像类)

判断对象死亡?引用计数 vs 可达性分析

引用计数算法:给对象添加一个引用计数器,每当有一个地方引用到他,就加1;引用失效就减1。有问题,有可能存在循环引用,导致对象无法被回收。

可达性分析算法:以GC Roots对象为起始点,从这些节点向下搜索

可以作为GC ROOT对象的有:Java虚拟机栈中的引用对象。本地方法栈中JNI(既一般说的Native方法)引用的对象。方法区中类静态属性所引用的对象。方法区中常量所引用的对象。

如何回收对象?垃圾收集算法

标记清除算法:分为标记和清除两个阶段。

首先从根集合进行扫描,对存活的对象进行标记,标记完毕后,再扫描整个空间中未被标记的对象并进行回收(老年代)

主要不足有两个:效率问题:标记和清除两个过程的效率都不高;

空间问题:不进行对象的移动,并且仅对不存活的对象进行处理,因此标记清除之后会产生大量不连续的内存碎片,可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

复制算法将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这种算法适用于对象存活率低的场景,比如新生代。

标记整理算法的标记过程类似标记清除算法,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存,类似于磁盘整理的过程,该垃圾回收算法适用于对象存活率高的场景(老年代)

垃圾收集器

Serial收集器(复制算法): 新生代单线程收集器,标记和清理都是单线程,优点是简单高效;

Serial Old收集器 (标记-整理算法): 老年代单线程收集器,Serial收集器的老年代版本;

ParNew收集器 (复制算法): 新生代并行收集器,实际上是Serial收集器的多线程版本,在多核CPU环境下有着比Serial更好的表现;

Parallel Old收集器 (标记-整理算法): 老年代并行收集器,吞吐量优先,Parallel Scavenge收集器的老年代版本;

CMS(Concurrent Mark Sweep)收集器(标记-清除算法): 老年代并行收集器,以获取最短回收停顿时间为目标的收集器,具有高并发、低停顿的特点,追求最短GC回收停顿时间。

收集过程分为:初始标记,并发标记,重新标记,垃圾回收

G1(Garbage First)收集器 (标记-整理算法): Java堆并行收集器,G1收集器是JDK1.7提供的一个新收集器,G1收集器基于“标记-整理”算法实现,也就是说不会产生内存碎片。此外,G1收集器不同于之前的收集器的一个重要特点是:G1回收的范围是整个Java堆(包括新生代,老年代),而前六种收集器回收的范围仅限于新生代或老年代。

 

分配回收策略(老年代新生代)

自动内存管理可以归结为自动化地解决两个问题:

分配内存、回收内存。

一般而言,对象主要分配在新生代的Eden区上,少数情况下也可能直接分配在老年代中。

1)    对象优先在Eden分配,当Eden区没有足够空间时,虚拟机将发起一次MinorGC。

2)    大对象直接进入老年代。所谓的大对象是指,很长的字符串以及数组。

3)    长期存活对象进入老年代。在新生代中经历n次(默认15)Minor GC后,晋升老年代。

4)    动态对象年龄判定。为了更好地适应不同程序的内存状况,虚拟机并不是永远地要求对象年龄必须达到了MaxTenuringThreshold才能晋升老年代,如果在Survivor空间中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到MaxTenuringThreshold中要求的年龄。

 

GC调优

各分区的大小对GC的性能影响很大。

如何将各分区调整到合适的大小,分析活跃数据的大小是很好的切入点。

活跃数据的大小是指,应用程序稳定运行时长期存活对象在堆中占用的空间大小,也就是Full GC后堆中老年代占用空间的大小。可以通过GC日志中Full GC之后老年代数据大小得出,比较准确的方法是在程序稳定后,多次获取GC数据,通过取平均值的方式计算活跃数据的大小

通过收集GC信息,结合系统需求,确定优化方案,例如选用合适的GC回收器、重新设置内存比例、调整JVM参数等。

根据对象生命周期的分布情况:如果应用存在大量的短期对象,应该选择较大的年轻代;如果存在相对较多的持久对象,老年代应该适当增大。

 

JVM常用参数

-Xms: 初始堆大小

-Xmx:最大堆大小

-XX:NewSize=n:设置年轻代大小

-XX:NewRatio=n:设置年轻代和年老代的比值。如:为3表示年轻代和年老代比值为1:3

-XX:SurvivorRatio=n:年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如3表示Eden:3 Survivor:2(3:1:1),一个Survivor区占整个年轻代的1/5

-XX:MaxPermSize=n:设置永久代大小

 

Cookie session

Cookie与Session都是用来跟踪浏览器用户身份的会话方式。

Cookie放客户浏览器,Session放服务器。

Cookie不安全,别人可以分析本地Cookie进行Cookie欺骗,用加密的Cookie或Session。

Session存服务器。占服务器性能,如果减轻负担方面,用Cookie。

单个Cookie在客户端的限制是4K,很多浏览器都限制一个站点最多保存20个Cookie。

网络分层

物理层:在传输媒体上传输数据比特流。屏蔽介质和通信手段差异,使数据链路层感觉不到

数据链路层:主机间有很多链路,为相邻结点间服务。把网络层传来的分组封装成帧。

网络层:为主机间提供传输服务,把运输层传递下来的报文段或数据报封装成分组。

运输层:进程间的通用数据传输服务。

         传输控制协议 TCP,提供面向连接、可靠的数据传输服务,数据单位为报文段;

         用户数据报协议 UDP,提供无连接数据传输服务,数据单位为用户数据报。

         TCP 主要提供完整性服务,UDP 主要提供及时性服务。

应用层:为特定应用程序提供数据传输服务,例如 HTTP、DNS 等。数据单位为报文。

握手挥手

序号seq :对字节流编号,序号为 301,编号为 301,如携带数据 100 字节,下一个报文段的序号应为 401。用来标记顺序

确认号 ack:期望收到的下一个报文段序号。例如 B 收到 A报文段序号为 501,长度 200 ,因此 B 期望701,B 发送给 A 的确认报文段中确认号就为 701。

确认 ACK :当 ACK=1 时确认号ack字段有效,否则无效。

同步 SYN :在连接建立时用来同步序号。当 SYN=1,ACK=0 时表示这是一个连接请求报文段。若对方同意建立连接,则响应报文中 SYN=1,ACK=1。

终止 FIN :用来释放一个连接,当 FIN=1 时,表示发送方已发送完毕,要求释放连接。

窗口 :窗口值作为接收方让发送方设置其发送窗口的依据。这个限制是因为接收方的数据缓存空间有限

 

1、第一次握手:客户端给服务器发送一个 SYN 报文。

2、第二次握手:服务器收到 SYN 报文之后,会应答一个 SYN+ACK 报文。

3、第三次握手:客户端收到 SYN+ACK 报文之后,会回应一个 ACK 报文。

4、服务器收到 ACK 报文之后,三次握手建立完成。

第一次:seq随机x,ACK=0,syn=1,ack=0,

第二次:seq随机y,ACK=X+1,syn=1,ack=1

第三次:seq=x+1,ACK=Y+1,syn=0,ack=1

第一次握手:客户端发,服务端收到。服务端就能得出结论:客户端的发送能力、服务端接收能力是正常

第二次握手:服务端发,客户端收到。客户端就能得出结论:服务端的接收发送能力,客户端的接收发送能力是正常的。服务器不能确认客户端的接收能力是否正常。

第三次握手:客户端发,服务端收到了。这样服务端就能得出结论:客户端的接收发送能力正常,服务器自己的发送、接收能力也正常。

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

客户端等待一个超时重传时间之后,就会重新请求连接。但是这个滞留的连接请求最后还是会到达服务器,如果不进行三次握手,那么服务器就会打开两个连接。

为什么三次四次?

三次:Server在收到建立连接请求后,可以直接把ACK和SYN放在一个报文发送给Client。

四次:关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,因此,己方ACK和FIN一般都会分开发送。

 

四次挥手:

客户机:我想和你断开连接,你同意吗?(FIN=1)             服务器:我同意(ACK=1)

(期间服务器可能还会向客户机发送数据,但是反之不可以)

服务器:客户机,我想要和你断开连接,你同意吗?(FIN=1) 客户机:我同意。(ACK=1)

 

短连接表示“业务处理+传输数据的时间 远远小于 TIMEWAIT超时的时间”的连接。

 

UDP想可靠

就要接收方收到UDP之后回复个确认包,发送方有个机制,收不到确认包就要重新发送,每个包有递增的序号,接收方发现中间丢了包就要发重传请求,当网络太差时候频繁丢包,防止越丢包越重传的恶性循环,要有个发送窗口的限制,发送窗口的大小根据网络传输情况调整,调整算法要有一定自适应性。

网络访问过程

域名解析

--> 发起TCP的3次握手 拿到域名对应的IP地址之后,浏览器向服务器的WEB程序(tomcat,nginx)80端口发起TCP连接请求。

--> 建立TCP连接后发http请求

--> 服务器响应http请求,浏览器得到html代码

--> 浏览器解析html代码,并请求html代码中的资源(如js、css、图片)

--> 浏览器对页面渲染呈现

 

域名解析:搜索浏览器的DNS缓存 操作系统的DNS缓存  hosts文件C:\\Windows 迭代DNS解析请求(根名称/顶级名称/二级名称/权威名称服务器)

 

为什么tcp可靠?

流量控制(滑动窗口)

发送方通过维持一个发送窗口确保不会发生发送方发太快接收方无法及时处理。

TCP如何保证可靠传输?

1、确认和重传:接收方收到报文就会确认,发送方发送一段时间后没有收到确认就重传。

2、数据校验

1)ack:数据丢失或延迟。发送时会起定时器,如果指定时间内没接收到ACK seq + 1,就再发一次。

2)数据乱序:接收方上一个收到的正确数据是seq + 4,它返回seq + 5作为ACK。这时候它收到了seq + 7,因为顺序错了,所以接收方会再次返回seq + 5给发送方。

3)数据错误:每一个TCP数据都会带着数据的校验和。接收方收到数据seq + 3以后会先对校验和进行验证。如果结果不对,则发送ACK seq + 3,让发送方重新发送数据。

4)数据重复:接收方直接丢弃重复数据。

3、流量控制:当接收方来不及处理发送方的数据,能提示发送方降低发送的速率,防止包丢失。

4、拥塞控制:当网络拥塞时,减少数据的发送。

流量控制与滑动窗口

流量控制是为了控制发送方发送速率,保证接收方来得及接收。

接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为0,则发送方不能发送数据。

发送方和接收方各有一个窗口,接收方通过窗口字段告诉发送方自己的窗口大小,发送方根据这个值和其它信息设置自己的窗口大小。

TCP使用累计确认(发送方一次发送多个连续包,接收方只需要确认最后一个包),快速重传(收到3个冗余的ACK包立马重传,不用等待超时)以及选择重传(只对丢失的包进行重传)提高效率

TCP的拥塞控制与拥塞窗口

拥塞控制:防止过多的数据注入到网络中,这样可以使网络中的路由器或链路不致过载。

发送方维持一个拥塞窗口 cwnd的状态变量。动态地在变化。发送方让自己的发送窗口等于拥塞。

原则:没拥塞,窗口就增大一些,以便把更多的分组发送出去。

出现拥塞,拥塞窗口就减小一些,以减少注入到网络中的分组数。

几种拥塞控制方法:慢开始、拥塞避免、快重传和快恢复。

慢开始:不清楚网络的负荷情况。因此先探测一下,由小到大逐渐增大发送窗口,也就是说,由小到大逐渐增大拥塞窗口数值。

通常在刚刚开始发送报文段时,先把拥塞窗口 cwnd 设置为一个最大报文段MSS的数值。而在每收到一个对新的报文段的确认后,把拥塞窗口增加至多一个MSS的数值。用这样的方法逐步增大发送方的拥塞窗口 cwnd ,可以使分组注入到网络的速率更加合理。

慢开始门限ssthresh的用法如下:

      当 cwnd < ssthresh 时,使用慢开始算法

当 cwnd > ssthresh 时,改用拥塞避免算法。

    当 cwnd = ssthresh 时,都可以

拥塞避免算法:经过一个往返时间RTT就把拥塞窗口cwnd加1,不是加倍。按线性规律缓慢增长,比慢开始算法的拥塞窗口增长速率缓慢得多。

只要发送方判断网络出现拥塞(其根据就是没有收到确认),就要把门限ssthresh设置为出现拥塞时的发送方窗口值的一半(但不能小于2)。然后把拥塞窗口cwnd重新设置为1,执行慢开始算法。目的就是要迅速减少主机发送到网络中的分组数,使得发生拥塞的路由器有足够时间把队列中积压的分组处理完毕。

快速恢复算法:发送方认为网络很可能没有发生拥塞,因此而是把cwnd值设置为门限减半后的数值,然后使拥塞窗口线性增大。

UDP可靠

最简单的方式是在应用层模仿传输层TCP的可靠性传输。下面不考虑拥塞处理,可靠UDP的简单设计。

 

1、添加seq/ack机制,确保数据发送到对端

2、添加发送和接收缓冲区,主要是用户超时重传。

3、添加超时重传机制。

详细说明:送端发送数据时,生成一个随机seq=x,然后每一片按照数据大小分配seq。数据到达接收端后接收端放入缓存,并发送一个ack=x的包,表示对方已经收到了数据。发送端收到了ack包后,删除缓冲区对应的数据。时间到后,定时任务检查是否需要重传数据。

 

目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。

HTTP and HTTPS

通信使用明文,内容可能被窃听(重要密码泄露)

不验证通信方身份,有可能遭遇伪装(跨站点请求伪造)

无法证明报文的完整性,有可能已遭篡改(运营商劫持)

http+加密+认证+完整性保护=https

1、https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

2、https则是通过TLS加密后传输。SSL 是“Secure Sockets Layer”的缩写,中文叫做“安全套接层”

3、http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

对称密钥加密,又称私钥加密,即发送方和接收方用同一个密钥去加密解密。优势是速度快,适合于对大数据量进行加密,但密钥管理困难。

非对称密钥加密,又称公钥加密,需要使用一对密钥分别完成加密和解密,一个公开发布,即公开密钥,另一个由用户自己保存,即私用密钥。信息发送者用公开密钥去加密,而信息接收者则用私用密钥去解密。

从功能角度而言非对称加密比对称加密功能强大,但加密和解密速度却比对称密钥加密慢得多。

SSL/TLS协议,公钥加密法,客户端先向服务器端索要公钥,然后用公钥加密信息,服务器收到密文后,用自己的私钥解密,如何保证公钥不被篡改?

解决方法:将公钥放在数字证书中,只要证书是可信的,公钥就是可信的。

HTTP方法及相互区别

GET 用于获取,而 POST 用于传输实体主体。

GET 和 POST 的请求都能使用额外的参数,但是 GET 的参数是以查询字符串出现在 URL 中,而 POST 的参数存储在实体主体中。不能因为 POST 参数存储在实体主体中就认为它的安全性更高,因为照样可以通过一些抓包工具(Fiddler)查看

因为 URL 只支持 ASCII 码,因此 GET 的参数中如果存在中文等字符就需要先进行编码。例如中文会转换为%E4%B8%AD%E6%96%87 ,而空格会转换为%20。POST参数支持标准字符集。

GET请求在URL中传送的参数是有长度限制的,而POST么有

HEAD获取报文首部,和 GET 方法类似,但是不返回报文实体主体部分

状态码

1正常2成功3重定向4客户端错误5服务端错误

100 Continue :表明到目前为止都很正常,客户端可以继续发送请求或者忽略这个响应。

200 OK

204 No Content :请求已经成功处理,但是返回的响应报文不包含实体的主体部分。一般在只需要从客户端往服务器发送信息,而不需要返回数据时使用。

206 Partial Content :表示客户端进行了范围请求,响应报文包含由 Content-Range 指定范围的实体内容。

301 Moved Permanently :永久性重定向

302 Found :临时性重定向

303 See Other :和 302 有着相同的功能,但是 303 明确要求客户端应该采用 GET 方法获取资源。

304 Not Modified :表示资源在由请求头中的If-Modified-Since或If-None-Match参数指定的这一版本之后,未曾被修改。在这种情况下,由于客户端仍然具有以前下载的副本,因此不需要重新传输资源。

307 Temporary Redirect :临时重定向,与302相反,当重新发出原始请求时,不允许更改请求方法。

400 Bad Request :请求报文中存在语法错误

401 Unauthorized :该状态码表示发送的请求需要有认证信息。如果之前已进行过一次请求,则表示用户认证失败

403 Forbidden :请求被拒绝

404 Not Found :请求失败,请求所希望得到的资源未被在服务器上发现,但允许用户的后续请求。

500 Internal Server Error :服务器正在执行请求时发生错误

503 Service Unavailable :服务器暂时处于超负载或正在进行停机维护,现在无法处理请求。

504 Gateway Timeout作为网关或者代理工作的服务器尝试执行请求时,未能及时从上游服务器

 

http结构

一个HTTP请求报文由四个部分组成:请求行、请求头部、空行、请求数据。

1.请求行:由请求方法字段、URL字段和HTTP协议版本字段3个字段组成,它们用空格分隔。比如 GET /data/info.html HTTP/1.1

方法字段就是HTTP使用的请求方法,比如常见的GET/POST

其中HTTP协议版本有两种:HTTP1.0/HTTP1.1 可以这样区别:

HTTP1.0对于每个连接都只能传送一个请求和响应,请求就会关闭,HTTP1.0没有Host字段;而HTTP1.1在同一个连接中可以传送多个请求和响应,多个请求可以重叠和同时进行,HTTP1.1必须有Host字段。

2.请求头部

指明请求类型(一般是GET或者 POST)。大多数请求头并不是必需的,但post的Content-Length除外。

Accept: 浏览器可接受的MIME类型。

Accept-Charset:浏览器可接受的字符集。

Accept-Encoding:浏览器能够进行解码的数据编码方式,比如gzip。

Accept-Language:浏览器所希望的语言种类

Authorization:授权信息,通常出现在对服务器发送的WWW-Authenticate头的应答中。

Content-Length:表示请求消息正文的长度。

Host: 客户机通过这个头告诉服务器,想访问的主机名。Host头域指定请求资源的Intenet主机和端口号,必须表示请求url的原始服务器或网关的位置。HTTP/1.1请求必须包含主机头域,否则系统会以400状态码返回。

Referer:客户机通过这个头告诉服务器,它是从哪个资源来访问服务器的(防盗链)。包含一个URL,用户从该URL代表的页面出发访问当前请求的页面。

User-Agent:User-Agent头域的内容包含发出请求的用户信息。浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用。

Cookie:客户机通过这个头可以向服务器带数据,这是最重要的请求头信息之一。

From:请求发送者的email地址,由一些特殊的Web客户程序使用,浏览器不会用到它。

Connection:处理完这次请求后是否断开连接还是继续保持连接。

同时指定几个范围:bytes=500-600,601-999

3.空行

它的作用是通过一个空行,告诉服务器请求头部到此为止。

4.请求数据

若方法字段是GET,则此项为空,没有数据

若方法字段是POST,则通常来说此处放置的就是要提交的数据

 

HTTP响应报文由三部分组成:响应行、响应头、响应体

1.响应行

响应行一般由协议版本、状态码及其描述组成 比如 HTTP/1.1 200 OK

其中协议版本HTTP/1.1或者HTTP/1.0,200就是它的状态码,OK则为它的描述。

//常见状态码:

100~199:表示成功接收请求,要求客户端继续提交下一次请求才能完成整个处理过程。

200~299:表示成功接收请求并已完成整个处理过程。常用200

300~399:为完成请求,客户需进一步细化请求。例如:请求的资源已经移动一个新地址、常用302(意味着你请求我,我让你去找别人),307和304(我不给你这个资源,自己拿缓存)

400~499:客户端的请求有错误,常用404(意味着你请求的资源在web服务器中没有)403(服务器拒绝访问,权限不够)

500~599:服务器端出现错误,常用500

2.响应头

响应头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据。

设置Cookie,指定修改日期,指示浏览器按照指定的间隔刷新页面,声明文档的长度以便利用持久HTTP连接,……等等许多其他任务。

 

常见的响应头字段含义:

Allow:服务器支持哪些请求方法(如GET、POST等)。

Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。

Content-Length:表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。

Content- Type:表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置 Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。

 

Date:当前的GMT时间,例如,Date:Mon,31Dec200104:25:57GMT。Date描述的时间表示世界标准时,换算成本地时间,需要知道用户所在的时区。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。

Location:这个头配合302状态码使用,用于重定向接收者到一个新URI地址。表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。

Refresh:告诉浏览器隔多久刷新一次,以秒计。

 

Set-Cookie:设置和页面关联的Cookie。Servlet不应使用response.setHeader(“Set-Cookie”, …),而是应使用HttpServletResponse提供的专用方法addCookie。

 

Transfer-Encoding:告诉浏览器数据的传送格式。

 

 

注:设置应答头最常用是HttpServletResponse的setHeader,方法有两个参数:应答头的名字和值。和设置状态代码相似,设置应答头应该在发送任何文档内容之前进行。

setDateHeader方法和setIntHeadr方法专门用来设置包含日期和整数值的应答头,前者避免了把Java时间转换为GMT时间字符串的麻烦,后者则避免了把整数转换为字符串的麻烦。

HttpServletResponse设置

setContentType:设置Content-Type头。大多数Servlet都要用到

以上是关于当年,兔子学姐靠这个面试小抄拿了个22k的主要内容,如果未能解决你的问题,请参考以下文章

当年,学姐总结奇安信18k常问面试题

当年学长把这份Java总结给我,让我普通二本校招拿到22K

《MySQL面试小抄》查询缓存机制终面

兔年说兔,那些年,我们碰到与兔相关的编程面试题

兔年说兔,那些年,我们碰到与兔相关的编程面试题

《MySQL面试小抄》索引失效场景验证