2021春招冲刺
12.25日
前言:今天的内容感觉难起来了,第一眼没有一个会的,而且每个问题其实都值得单独地写一篇博客来从原理性地记录 > - <,但是为了归纳方便还是以后积累多了再专门再写相关分类的博客吧。
写到单例模式的感想:太多了55555 从零开始学习所以这一篇写了两天才写完
1.计算机网络 | TCP与UDP的区别
边记录边学,参考了很多博客,主要有 参考博客1 | 参考博客2 | 参考博客3 | 邹大佬的博客
1.关于TCP/IP
在介绍TCP与UDP之前,首先要介绍一下TCP/IP。它是一个协议簇,而TCP与UDP正是其中有两个具有代表性的传输层协议。TCP/IP按照自底向上可以分为四层: 链路层、网络层、传输层和应用层。
- 链路层: 负责封装和解封装IP报文,发送和接受ARP/RARP报文等
-
网络层: 负责路由以及把分组报文发送给目标网络或主机。
包括Internet协议(IP)、Internet控制信息协议(ICMP)、地址解析协议(ARP)、反向地址解析协议(RARP) - 传输层: 负责对报文进行分组和重组,并以TCP或UDP协议格式封装报文。
-
应用层: 负责向用户提供应用程序比如:
- 超文本传输协议(HTTP): 万维网的基本协议;
- 件传输(TFTP): 简单文件传输协议;
- 远程登录(Telnet): 提供远程访问其它主机功能, 它允许用户登录internet主机,并在这台主机上执行命令;
- 域名系统(DNS): 该系统用于在internet中将域名及其公共广播的网络节点转换成IP地址。
- 网络管理(SMTP): 该协议提供了监控网络设备的方法, 以及配置管理,统计信息收集,性能管理及安全管理等;
2.UDP
UDP协议全称是用户数据报协议,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。
-
特点
-
无连接:
知道对端的IP和端口号就直接进行传输, 不需要建立连接。而TCP需要TCP在发送数据前进行三次握手建立连接。
同时因此也不需要维护连接状态,包括收发状态等, 一台服务机可同时向多个客户机传输相同的消息。 -
不可靠:
没有确认机制, 没有重传机制,没有拥塞机制; 如果因为网络故障该段无法发到对方, UDP协议层不会给应用层返回任何错误信息而导致丢包。
同时不关心发送端是否收到了数据,也对数据进行校验与备份。 -
面向报文:
不能够灵活的控制读写数据的次数和数量,应用层交给UDP多长的报文, UDP原样发送, 既不会拆分, 也不会合并,而是保留这些报文的边界。因此,应用程序需要选择合适的报文大小。 -
有单播,多播,广播的功能:
UDP 不止支持一对一的传输方式,同样支持一对多,多对多,多对一的方式,也就是说 UDP 提供了单播,多播,广播的功能。 -
头部开销小:
UDP 的首部开销小,只有 8 个字节,比 TCP 的 20 个字节的首部要少得多。
UDP 头部包含了以下几个数据:
1)两个十六位的端口号,分别为源端口(可选字段)和目标端口。
2)整个数据报文的长度(十六位)。
3)整个数据报文的检验和(IPv4 可选 字段),该字段用于发现头部信息和数据中的错误(十六位)。
因此 UDP 的头部开销小,只有八字节,相比 TCP 的至少二十字节要少得多,在传输数据报文时是很高效的。
-
无连接:
- 适用场景
对当前网络通讯质量要求不高的时候,实时性要求高的地方都可以看到 UDP 的身影,要求网络通讯速度尽量的快,这时就使用UDP。
3.TCP
TCP协议全称是传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,由 IETF 的RFC793定义。
-
TCP建立连接过程
三次握手特点:- 没有应用层的数据 ,SYN这个标志位只有在TCP建立连接时才会被置1 ,握手完成后SYN标志位被置0。
第一次握手:
- 客户端向服务端发送连接请求报文段(SYN J)。该报文段中包含自身的数据通讯初始序号。请求发送后,客户端便进入 SYN-SENT(请求连接)状态。
第二次握手:
- 服务端收到连接请求报文段后,如果同意连接,则会发送一个应答,该应答中也会包含自身的数据通讯初始序号(SYN K,ACK,seq,ack=J+1),发送完成后便进入 SYN-RECEIVED 状态。
第三次握手:
- 当客户端收到连接同意的应答后,还要向服务端发送一个确认报文(ACK,seq,ack=K+1)。发送完毕,客户端和服务端都进入ESTABLISHED状态,此时连接建立成功。
Question:为什么 TCP 建立连接需要三次握手,而不是两次:
1.防止出现失效的连接请求报文段被服务端接收的情况,从而产生错误
2.客户端链接超时,会重新发送一次连接请求。当两个SYN都抵达发送了ACK时,虽然第一个ACK会被放弃,但是服务器端会分配资源并一直维持这个资源,造成浪费。
-
TCP断开连接过程
挥手特点:- TCP 是全双工的,在断开连接时两端都需要发送 FIN 和 ACK。
第一次挥手:
- 当主机A(客户端) 完成数据传输后,将控制位FIN置1,提出停止TCP连接的请求
第二次挥手:
- B(服务端) 收到连接释放请求后,会告诉应用层要释放 TCP 链接。然后会发送 ACK 包(ack M+1),并进入 CLOSE_WAIT 状态。
- 此时表明 A 到 B 的连接已经释放,不再接收 A 发的数据了。但是因为 TCP 连接是双向的,所以 B 仍旧可以发送数据给 A。
第三次挥手:
- B果此时还有没发完的数据会继续发送,完毕后会向 A 发送连接释放请求(FIN N),然后 B 便进入 LAST-ACK 状态。
第四次挥手:
- A 收到释放请求后,向 B 发送确认应答,此时 A 进入 TIME-WAIT 状态。
- 该状态会持续 2MSL(最大段生存期,指报文段在网络中生存的时间,超时会被抛弃) 时间,若该时间段内没有 B 的重发请求的话,就进入 CLOSED 状态。当 B 收到确认应答后,也便进入 CLOSED 状态。
-
TCP头部格式
- 源端口 16位;目标端口 16位;序列号 32位;回应序号 32位;TCP头长度 4位;reserved 6位;控制代码 6位;窗口大小 16位;偏移量 16位;校验和 16位;选项 32位(可选);
- 这样我们得出了TCP包头的最小长度,为20字节。
-
TCP特点
- 面向连接的运输层协议: 发送数据之前必须在两端建立连接,即进行三次握手。
-
可靠传输:
- 提供拥塞控制,当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞。
- 误码靠的是TCP的段编号以及确认号判断丢包。TCP为了保证报文传输的可靠,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。
- 提供全双工通信: TCP允许通信双方的应用程序在任何时候都能发送数据,因为TCP连接的两端都设有缓存,用来临时存放双向通信的数据。当然,TCP可以立即发送一个数据段,也可以缓存一段时间以便一次发送更多的数据段(最大的数据段大小取决于MSS)
- 仅支持单播传输: 每条TCP传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式。
- 面向字节流: TCP不像UDP一样那样一个个报文独立地传输,而是在不保留报文边界的情况下以字节流方式进行传输。
-
TCP与UDP的区别
TCP UDP 是否连接 面向连接,建立连接3次握手,断开连接4次挥手 无连接 是否可靠 可靠传输,使用流量控制和拥塞控制 不可靠传输,不使用流量控制和拥塞控制 连接对象个数 只能是一对一通信 支持一对一,一对多,多对一和多对多交互通信 传输方式 面向字节流 面向报文 首部开销 首部最小20字节,最大60字节 首部开销小,仅8字节 适用场景 适用于要求可靠传输的应用,例如文件传输 适用于实时应用(IP电话、视频会议、直播等)
2.设计模式 | 用Class与Function的方式分别实现一个单例模式的案例
要命啊,每次都要先从原理搞起。啥都没学,甚至不会java,先去弄懂什么是单例模式了(泪目)接下来的内容全部来自菜鸟教程以及 搬运博客
单例模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
-
注意:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
-
实现:
- 将该类的构造方法定义为私有方法,这样其他处的代码就无法通过调用该类的构造方法来实例化该类的对象,只有通过该类提供的静态方法来得到该类的唯一实例;
- 在该类内提供一个静态方法,当我们调用这个方法时,如果类持有的引用不为空就返回这个引用,如果类保持的引用为空就创建该类的实例并将实例的引用赋予该类保持的引用
-
优点
- 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
- 避免对资源的多重占用(比如写文件操作)。
- 为整个系统提供一个全局访问点。
-
缺点
- 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
- 如果实例化的对象长时间不被利用,系统会认为该对象是垃圾而被回收,这可能会导致对象状态的丢失;
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为的单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;
- 不适用于变化频繁的对象;
-
适用场景
- 要求生产唯一序列号。
- 需要频繁实例化然后销毁的对象。
- 创建对象时耗时过多或者耗资源过多,但又经常用到的对象,比如 I/O 与数据库的连接等。
- 方便资源相互通信的环境。
-
构造方法 · 使用class
- 饿汉式:
在类装载的时候就完成实例化。避免了线程同步问题。同样,在类装载的时候就完成实例化,没有达到Lazy Loading的效果。如果从始至终从未使用过这个实例,则会造成内存的浪费。// 饿汉式单例 public class Singleton1 { // 指向自己实例的私有静态引用,主动创建 private static Singleton1 singleton1 = new Singleton1(); // 私有的构造方法 private Singleton1(){} // 以自己实例为返回值的静态的公有方法,静态工厂方法 public static Singleton1 getSingleton1(){ return singleton1; } }
- 懒汉式:
单例实例被延迟加载,即只有在真正使用的时候才会实例化一个对象并交给自己的引用。但是只能在单线程下使用。如果在多线程下,一个线程进入了if (singleton == null)判断语句块,还未来得及往下执行,另一个线程也通过了这个判断语句,这时便会产生多个实例。所以在多线程环境下不可使用这种方式。
看了邹大佬的博客感觉有点像懒汉法,如果不存在就创建,存在就返回?。// 懒汉式单例 public class Singleton2 { // 指向自己实例的私有静态引用 private static Singleton2 singleton2; // 私有的构造方法 private Singleton2(){} // 以自己实例为返回值的静态的公有方法,静态工厂方法 //当然,可以使用同步方法public static synchronized Singleton2 getInstance2(),但是效率不高 public static Singleton2 getSingleton2(){ // 被动创建,在真正需要使用时才去创建 if (singleton2 == null) { singleton2 = new Singleton2(); } return singleton2; } }
- c#提供的静态初始化
//阻止发生派生,而派生可能会增加实例 public sealed class Singleton { private Singleton() { } //在第一次引用类的任何成员时创建实例,公共语言运行库负责处理变量初始化 private static readonly Singleton instance=new Singleton(); public static Singleton GetInstance() { return instance; } }
- java内部类式单例类
public class Singleton { private Singleton(){} private class SingletonHoledr(){ private static Singleton instance = new Singleton(); } private static Singleton getInstance(){ return SingletonHoledr.instance; } }
- 双检锁方法由于nstance = new Singleton()这行代码在不同编译器上的行为是无法预知的,导致在很多平台和优化编译器上是错误的,在此就不记录。其实是因为大半夜电脑没电了,记录一下function闭包实现就byebye
- 饿汉式:
-
构造方法 · 使用function
直接去学长博客看了参考答案,即使用闭包的方法。function SingleDog() { this.show = function () { console.log('w w w w') } } SingleDog.getInstance = (function () { let instance = null return function () { if (!instance) { instance = new SingleDog() } return instance } })() let a = SingleDog.getInstance() let b = SingleDog.getInstance() console.log(a === b) // true
3.浏览器 | 什么是回流与重绘?
-
浏览器渲染的流程
这一点在16号关于css的问题中其实已经提到,此处在那基础上进行一点补充- 在页面加载时,浏览器解析html文件,生成DOM Tree(含了所有HTML标签,包括display:none隐藏,还有用JS动态添加的元素等)
- 浏览器解析CSS文件生成CSSOM Tree
- 将Dom Tree和CSSOM Tree结合,生成Render Tree (render tree能识别样式,且其中每个NODE都有自己的style,而且render tree不包含隐藏的节点。比如display:none的节点,还有head节点。因为这些节点不会用于呈现,而且不会影响呈现的)
- 根据Render Tree渲染绘制,将像素渲染到屏幕上。
-
什么是回流(Layout)(又称重排)
- 当渲染树中的一部分或者全部因为元素的尺寸、布局、隐藏等改变而需要重新构建的时候,这时候就会发生回流,得到节点的几何信息(位置、大小)。
- 每个页面都至少发生一次回流,也就是页面第一次加载的时候,因为此时正在构建render tree。
- 在回流的时候,浏览器会使渲染树中受到影响的元素部分失效,并重新绘制这个部分的渲染树。
-
什么是重绘(Painting)
- 完成回流以后,浏览器会重新绘制受到影响的部分元素到屏幕中,这个过程就是重绘,得到节点的绝对像素。
- 当render tree中的一些元素需要更新属性,而这些属性只是影响元素的外观,风格,而不会影响布局的,比如background-color。则就叫称为重绘。
-
什么时候发生回流与重绘
- 发生回流
- 添加或删除可见的DOM元素
- 元素的位置发生变化
- 元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
- 内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
- 页面第一次渲染的时候
- 浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
- 发生回流一定会引起重绘,但是重绘不一定发生回流
- 比如背景色、文字色、可见性(可见性这里特指形如visibility: hidden这样不改变元素位置和存在性的、单纯针对可见性的操作,注意与display:none进行区分)等
- 发生回流
4.浏览器 | 浏览器中存储数据的方案有哪几种
5.css | 实现一个雪花飘落的动画