应用层:为用户的应用进程提供网络通信服务
表示层:处理用户信息的表示问题,数据的编码,压缩和解压缩,数据的加密和解密
会话层:负责在网络中的两节点之间建立、维持和终止通信
传输层:在源端与目的端之间提供可靠的透明数据传输
网络层:将网络地址翻译成对应的物理地址,并通过路由选择算法为分组通过通信子网选择最适当的路径。
数据链路层:接收来自物理层的位流形式的数据,并封装成帧,传送到上一层
物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
是否面向连接 | 可靠性 | 传输形式 | 传输效率 | 消耗资源 | |
---|---|---|---|---|---|
TCP | 面向连接 | 可靠 | 字节流 | 慢 | 多 |
UDP | 无连接 | 不可靠 | 数据报文段 | 快 | 少 |
客户端向服务器端发送连接报文
服务器端接到连接请求时发送确认报文
socket就在应用程序的传输层和应用层之间,设计了一个socket抽象层,传输层的底一层的服务提供给socket抽象层
服务器端:
其过程是首先服务器方要先启动,并根据请求提供相应服务:
(1)打开一通信通道并告知本地主机,它愿意在某一公认地址上的某端口(如FTP的端口可能为21)接收客户请求;
(2)等待客户请求到达该端口;
(3)接收到客户端的服务请求时,处理该请求并发送应答信号。接收到并发服务请求,要激活一新进程来处理这个客户请求(如UNIX系统中用fork、exec)。新进程处理此客户请求,并不需要对其它请求作出应答。服务完成后,关闭此新进程与客户的通信链路,并终止。
(4)返回第(2)步,等待另一客户请求。
(5)关闭服务器
客户端:
(1)打开一通信通道,并连接到服务器所在主机的特定端口;
(2)向服务器发服务请求报文,等待并接收应答;继续提出请求…
(3)请求结束后关闭通信通道并终止。
首先调用close()发起主动关闭的一方,在发送最后一个ACK之后会进入time_wait的状态,也就说该发送方会保持2MSL时间之后才会回到初始状态。
time_wait状态产生的原因
1)为实现TCP全双工连接的可靠释放
2)为使旧的数据包在网络因过期而消失
为了确保连接到服务器端,且连接稳定,确保传输数据时候不会发生丢包,简单可靠地通信信道
校验和
计算方式:在数据传输的过程中,将发送的数据段都当做一个16位的整数。将这些整数加起来。并且前面的进位不能丢弃,补在后面,最后取反,得到校验和。
发送方:在发送数据之前计算检验和,并进行校验和的填充。
接收方:收到数据后,对数据以同样的方式进行计算,求出校验和,与发送方的进行比对
如果接收方比对校验和与发送方不一致,那么数据一定传输有误。但是如果接收方比对校验和与发送方一致,数据不一定传输成功。
确认应答+序列号
序列号:TCP传输时将每个字节的数据都进行了编号,这就是序列号。
确认应答:TCP传输的过程中,每次接收方收到数据后,都会对传输方进行确认应答。也就是发送ACK报文。这个ACK报文当中带有对应的确认序列号,告诉发送方,接收到了哪些数据,下一次的数据从哪里发。
超时重传
在进行TCP传输时,由于确认应答与序列号机制,也就是说发送方发送一部分数据后,都会等待接收方发送的ACK报文,并解析ACK报文,判断数据是否传输成功。如果发送方发送完数据后,迟迟没有等到接收方的ACK报文,这该怎么办呢?而没有收到ACK报文的原因可能是什么呢?
首先,发送方没有介绍到响应的ACK报文原因可能有两点:
数据在传输过程中由于网络原因等直接全体丢包,接收方根本没有接收到。
接收方接收到了响应的数据,但是发送的ACK报文响应却由于网络原因丢包了。
TCP在解决这个问题的时候引入了一个新的机制,叫做超时重传机制。简单理解就是发送方在发送完数据后等待一个时间,时间到达没有接收到ACK报文,那么对刚才发送的数据进行重新发送。如果是刚才第一个原因,接收方收到二次重发的数据后,便进行ACK应答。如果是第二个原因,接收方发现接收的数据已存在(判断存在的根据就是序列号,所以上面说序列号还有去除重复数据的作用),那么直接丢弃,仍旧发送ACK应答。
那么发送方发送完毕后等待的时间是多少呢?如果这个等待的时间过长,那么会影响TCP传输的整体效率,如果等待时间过短,又会导致频繁的发送重复的包。如何权衡?
由于TCP传输时保证能够在任何环境下都有一个高性能的通信,因此这个最大超时时间(也就是等待的时间)是动态计算的。
流量控制
在TCP协议的报头信息当中,有一个16位字段的窗口大小。在介绍这个窗口大小时我们知道,窗口大小的内容实际上是接收端接收数据缓冲区的剩余大小。这个数字越大,证明接收端接收缓冲区的剩余空间越大,网络的吞吐量越大。接收端会在确认应答发送ACK报文时,将自己的即时窗口大小填入,并跟随ACK报文一起发送过去。而发送方根据ACK报文里的窗口大小的值的改变进而改变自己的发送速度。如果接收到窗口大小的值为0,那么发送方将停止发送数据。并定期的向接收端发送窗口探测数据段,让接收端把窗口大小告诉发送端。
16位的窗口大小最大能表示65535个字节(64K),但是TCP的窗口大小最大并不是64K。在TCP首部中40个字节的选项中还包含了一个窗口扩大因子M,实际的窗口大小就是16为窗口字段的值左移M位。每移一位,扩大两倍。
拥塞控制
TCP传输的过程中,发送端开始发送数据的时候,如果刚开始就发送大量的数据,那么就可能造成一些问题。网络可能在开始的时候就很拥堵,如果给网络中在扔出大量数据,那么这个拥堵就会加剧。拥堵的加剧就会产生大量的丢包,就对大量的超时重传,严重影响传输。
所以TCP引入了慢启动的机制,在开始发送数据时,先发送少量的数据探路。探清当前的网络状态如何,再决定多大的速度进行传输。这时候就引入一个叫做拥塞窗口的概念。发送刚开始定义拥塞窗口为 1,每次收到ACK应答,拥塞窗口加 1。在发送数据之前,首先将拥塞窗口与接收端反馈的窗口大小比对,取较小的值作为实际发送的窗口。
拥塞窗口的增长是指数级别的。慢启动的机制只是说明在开始的时候发送的少,发送的慢,但是增长的速度是非常快的。为了控制拥塞窗口的增长,不能使拥塞窗口单纯的加倍,设置一个拥塞窗口的阈值,当拥塞窗口大小超过阈值时,不能再按照指数来增长,而是线性的增长。在慢启动开始的时候,慢启动的阈值等于窗口的最大值,一旦造成网络拥塞,发生超时重传时,慢启动的阈值会为原来的一半(这里的原来指的是发生网络拥塞时拥塞窗口的大小),同时拥塞窗口重置为 1。
TCP 粘包是指:发送方发送的若干个包数据到接收方接收时,粘成一个包数据。
TCP 是基于字节流的,虽然应用层和 TCP 传输层之间的数据交互是大小不等的数据块,但是 TCP 把这些数据块仅仅看成一连串无结构的字节流,没有边界,这就可能导致字节流合并(粘包)。
① 发送方产生的粘包
采用 TCP 协议传输数据的客户端与服务器经常是保持一个长连接的状态(一次连接发一次数据不存在粘包),双方在连接不断开的情况下,可以一直传输数据。但当发送的数据包过于的小时,那么 TCP 协议默认的会启用 Nagle 算法,将这些较小的数据包进行合并发送(缓冲区数据发送是一个堆压的过程);这个合并过程就是在发送缓冲区中进行的,也就是说数据发送出来它已经是粘包的状态了。
**总结:**要发送的数据小于 TCP 发送缓冲区的大小,TCP 将多次写入缓冲区的数据一次发送出去,将会发生粘包。
② 接受方产生的粘包
接收方采用 TCP 协议接收数据时的过程是这样的:数据到接收方,从网络模型的下方传递至传输层,传输层的 TCP 协议处理是将其放置接收缓冲区,然后由应用层来主动获取(例如C 语言用函数等);这时会出现一个问题,就是我们在程序中调用的读取数据函数不能及时的把缓冲区中的数据拿出来,而下一个数据又到来并有一部分放入的缓冲区末尾,等我们读取数据时就是一个粘包。(放数据的速度 > 应用层拿数据速度)。
**总结:**接收数据端的应用层没有及时读取缓冲区中的数据,导致缓冲区数据堆积,将发生粘包。
避免粘包有以下两种方式:
TCP有一个包活计时器,如果客户端出现异常,服务器不会一直等待下去,在接受到客户端请求时会重新复位计时器,2小时,之后会每隔75秒发送一个探测报文,发送10次没有反应就断开
ARP协议属于网络层的协议,主要作用是实现从IP地址转换为MAC地址。在每个主机或者路由器中都建有一个ARP缓存表,表中有IP地址及IP地址对应的MAC地址。
超文本传输协议,用于客户端和服务器端的通信
优点:跨平台 简单 灵活
HTTP 协议的特性「无状态、明文传输」既是优点也是缺点
常见字段:
Host字段:指定服务器的域名
Content_Length:表明本次相应的数据长度
Connection: 客户端要求服务器使用TCP持久连接
Content-Type: 服务器回应时,本次数据格式
Content-Encoding : 返回数据使用的压缩格式
服务器不用记忆http状态,不需要额外自愿记录状态信息,减轻服务器负担
没有记忆能力,在关联性的操作上会非常麻烦
方便阅读,通过F12或抓包直接肉眼查看
但是这样的话会将所有信息暴露出来,可能会被窃取
DNS域名解析 tcp连接 发送http请求 服务器处理请求并返回http报文关闭 TCP 连接:四次挥手 浏览器渲染 结束
1.首先进行域名解析,域名解析具体过程讲一下: 应用层
本地域名服务器向根域名服务器发起请求,根域名服务器返回com域的顶级域名服务器的地址;
本地域名服务器向com域的顶级域名服务器发起请求,返回权限域名服务器地址;
本地域名服务器向权限域名服务器发起请求,得到IP地址;
2.浏览器发起HTTP请求;应用层
3.接下来到了==传输层==,选择传输协议,TCP或者UDP,TCP是可靠的传输控制协议,对HTTP请求进行封装,加入了端口号等信息;
4.然后到了==网络层,通过IP协议将IP地址封装为IP数据报;然后此时会用到ARP协议==,主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址,找到目的MAC地址;
5.接下来到了==数据链路层==, 交换机 把网络层交下来的IP数据报添加首部和尾部,封装为MAC帧,现在根据目的mac开始建立TCP连接,三次握手,接收端在收到物理层上交的比特流后,根据首尾的标记,识别帧的开始和结束,将中间的数据部分上交给网络层,然后层层向上传递到应用层;
6.服务器响应请求并请求客户端要的资源,传回给客户端;
7.断开TCP连接,浏览器对页面进行渲染呈现给客户端。
DNS(Domain Name System)域名系统,将主机域名转换为ip地址,属于应用层协议,使用UDP传输。
它作为将[域名]和[IP地址]的一个[分布式数据库],能够使人更方便地访问[互联网].
过程:
总结: 浏览器缓存,系统缓存,路由器缓存,IPS服务器缓存,根域名服务器缓存,顶级域名服务器缓存,主域名服务器缓存。
一、主机向本地域名服务器的查询一般都是采用递归查询。
二、本地域名服务器向根域名服务器的查询的迭代查询。
1)当用户输入域名时,浏览器先检查自己的缓存中是否 这个域名映射的ip地址,有解析结束。
2)若没命中,则检查操作系统缓存(如Windows的hosts)中有没有解析过的结果,有解析结束。
3)若无命中,则请求本地域名服务器解析( LDNS)。
4)若LDNS没有命中就直接跳到根域名服务器请求解析。根域名服务器返回给LDNS一个 主域名服务器地址。
5) 此时LDNS再发送请求给上一步返回的gTLD( 通用顶级域), 接受请求的gTLD查找并返回这个域名对应的Name Server的地址
6) Name Server根据映射关系表找到目标ip,返回给LDNS
7) LDNS缓存这个域名和对应的ip, 把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束.
Cookie一般用来保存用户信息,Session通过服务器记录用户状态
cookie保存在客户端,session保存在服务器端
session安全性高.cookie若要存储敏感信息,最好加密,在使用时在服务器端解密
cookie记录用户信息,session记录用户状态
jwt: 在服务器端生成一个token, 3部分: 头(加密方式)+用户信息+秘钥
可以,Session的作用是在服务端来保持状态,通过sessionid来进行确认身份,但sessionid一般是通过Cookie来进行传递的。如果Cooike被禁用了,可以通过在URL中传递sessionid。
get和post底层都是tcp连接的
get : 获取 参数在地址中传输, 大小受限,不安全
post:发送 参数不可见,在请求体 数据大小不限制 安全
① 安全性区别:HTTP 是超文本传输协议,信息是明文传输,存在安全风险的问题。HTTPS 可以保证信息传输安全,在 TCP 和 HTTP 网络层之间加入了 SSL/TLS 安全协议,使得报文能够加密传输。
② 建里连接流程区别:HTTP 连接建立相对简单, TCP 三次握手之后便可进行 HTTP 的报文传输。而 HTTPS 在 TCP 三次握手之后,还需进行 SSL/TLS 的握手过程,才可进入加密报文传输。
③ 端口区别:HTTP 的端口号是 80,HTTPS 的端口号是 443。
④ 是否需要申请数字证书:HTTPS 协议需要向 CA(证书权威机构)申请数字证书,来保证服务器的身份是可信的。而 HTTP 协议不需要。
URI:是统一资源标志符,可以唯一标识一个资源。
URL:是统一资源定位符,可以提供该资源的路径。URL 是 URI 的一个子集,它不仅唯一标识资源,而且还提供了定位该资源的信息。
对称加密算法:双方持有相同的密钥,进行加密速度快,典型对称加密算法:DES、AES。
非对称加密算法:密钥成对出现(私钥、公钥),私钥只有自己知道,不在网络中传输;而公钥可以公开。相比对称加密速度较慢,典型的非对称加密算法有:RSA、DSA。
对称加密算法是指加密和解密采用相同的密钥,是可逆的(即可解密)。
优点: 加速密码快
**缺点:**密钥的传递和保存是一个问题,参与加密和解密的双方使用的密钥是一样的,这样密钥就很容易泄露
非对称加密算法是指加密和解密采用不同的密钥(公钥和私钥),因此非对称加密也叫公钥加密,是可逆的(即可解密)。
优点 : 加密和解密的密钥不一致,公钥是可以公开的,只需保证私钥不被泄露即可,这样就密钥的传递变的简单很多,从而降低了被破解的几率。
缺点 : 加密速度慢
RSA加密算法既可以用来做数据加密,也可以用来数字签名。
Https 采用对称加密和非对称加密,将服务器公钥放在数字证书 中,解决窃听风险
在通信建立前采用非对称加密交换会话秘钥,后续不再使用非对称加密
在通信过程中使用对称加密的会话秘钥方式加密铭文数据
SSL代表安全套接字层。它是一种用于加密和验证应用程序(如浏览器)和Web服务器之间发送的数据的协议。 身份验证 , 加密Https的加密机制是一种共享密钥加密和公开密钥加密并用的混合加密机制。
SSL/TLS协议作用:认证用户和服务,加密数据,维护数据的完整性的应用层协议
加密和解密需要两个不同的密钥,故被称为非对称加密;
加密和解密都使用同一个密钥的 对称加密。
优点在于加密、解密效率通常比较高,
HTTPS 是基于非对称加密的, 公钥是公开的,
(1)客户端向服务器端发起SSL连接请求;
(2) 服务器把公钥发送给客户端,并且服务器端保存着唯一的私钥
(3)客户端用公钥对双方通信的对称秘钥进行加密,并发送给服务器端
(4)服务器利用自己唯一的私钥对客户端发来的对称秘钥进行解密,
(5)进行数据传输,服务器和客户端双方用公有的相同的对称秘钥对数据进行加密解密,可以保证在数据收发过程中的安全,即是第三方获得数据包,也无法对其进行加密,解密和篡改。
因为数字签名、摘要是证书防伪非常关键的武器。 “摘要”就是对传输的内容,通过hash算法计算出一段固定长度的串。然后,在通过CA的私钥对这段摘要进行加密,加密后得到的结果就是“数字签名”.
servlet有getSession(),先获取Session,往Session方属性,底层服务器在检测待使用getSession后会产生一个32长度的随机串作为key,再创建Session对象,作为值
Session列表是一个map,当用户发出第一个请求时,服务器将字符串包装成一个Cookie发给客户端,浏览器收到会放在浏览器缓存,当客户端再次发起请求时,目的是从Session中读取数据,
先会将浏览器的Cookie放在请求头中,发给服务器端,服务器接收后会拿这JSessionId,去列表中查找,找到对应的value
HTTP 1.0:默认使用短连接,浏览器每次请求都需要与服务器建立一次 TCP 连接,服务器处理完成后立即断开 TCP 连接(无连接),服务端不记录客户端的请求状态(无状态)。
HTTP 1.1:默认使 用长连接,用以保持连接特性。在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输 HTTP 数据的 TCP 连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。
HTTP 2.0:引入二进制数据帧和流的概念,支持多路复用、服务器推送,支持使用二进制格式传输数据,而 HTTP 1.0 依然使用文本格式传输。
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。而从HTTP/1.1起,默认使用长连接,用以保持连接特性。
Https是在http和tcp之间加了一个ssl/tls 协议
SSL/TLS 协议基本流程:
客户端向服务器索要并验证服务器的公钥。
双方协商生产「会话秘钥」。
双方采用「会话秘钥」进行加密通信。
2XX
3XX
4XX
5XX
前端解决
后端解决
java过滤器过滤
response.setHeader("Access-Control-Allow-Origin", "192.168.31.2");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
后台配置同源Cors
在SpringBoot2.0 上的跨域 用以下代码配置 即可完美解决你的前后端跨域请求问题
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
/*是否允许请求带有验证信息*/
corsConfiguration.setAllowCredentials(true);
/*允许访问的客户端域名*/
corsConfiguration.addAllowedOrigin("*");
/*允许服务端访问的客户端请求头*/
corsConfiguration.addAllowedHeader("*");
/*允许访问的方法名,GET POST等*/
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
反射之中包含了一个「反」字,所以想要解释反射就必须先从「正」开始解释。
Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。
一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的。于是我们直接对这个类进行实例化,之后使用这个类对象进行操作。
Apple apple = new Apple(); //直接初始化,「正」
apple.setPrice(4);
上面这样子进行类对象的初始化,我们可以理解为「正」。
而反射则是一开始并不知道我要初始化的类对象是什么,自然也无法使用 new 关键字来创建对象了。
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
API:
Class类
Class clz = Class.forName("com.ff.api.Apple");
Constructor appleConstructor = clz.getConstructor();
Object appleObj = appleConstructor.newInstance();
Method setPriceMethod = clz.getMethod("setPrice", int.class);
setPriceMethod.invoke(appleObj, 14);
Field field = clz.getField("price");
boolean isPrimitive = class1.isPrimitive();//判断是否是基础类型
boolean isArray = class1.isArray();//判断是否是集合类
boolean isAnnotation = class1.isAnnotation();//判断是否是注解类
boolean isInterface = class1.isInterface();//判断是否是接口类
boolean isEnum = class1.isEnum();//判断是否是枚举类
String simpleName = class1.getSimpleName();//获取class类名
int modifiers = class1.getModifiers();//获取class访问权限
Class<?>[] declaredClasses = class1.getDeclaredClasses();//内部类
Class<?> declaringClass = class1.getDeclaringClass();//外部类
Annotation[] annotations = class1.getAnnotations();//获取class对象的所有注解
Class parentClass = class1.getSuperclass();//获取class对象的父类
Class<?>[] interfaceClasses = class1.getInterfaces();//获取class对象的所有接口
优点:
运行期类型的判断,动态类加载,动态代理使用反射。 代理对象
缺点:
性能是一个问题,反射相当于一系列解释操作,通知jvm要做的事情,性能比直接的java代码要慢很多。