TCP是怎么保证可靠的

TCP协议通过多种机制来保证数据的可靠传输。

首先,它使用确认应答机制,确保每个数据包都被接收方确认。

其次,序列号用于数据的有序传输,接收方可以根据序列号来检测丢失或重复的数据包。

第三,超时重传机制允许发送方在未收到确认应答时重新发送数据包。

第四,流量控制机制使用滑动窗口机制来进行流量控制,避免发送方过快发送数据导致接收方来不及处理

第五,使用拥塞控制算法,如慢启动、拥塞避免、快重传、快恢复,避免网络拥塞,确保数据包的可靠传输

第六,错误检测机制通过校验和来检测数据传输中的错误。

最后,TCP强大的状态机确保了连接的可靠建立和释放。

这些机制共同作用,使得TCP协议能够提供可靠的数据传输服务。

简述

ACK确认序列号,超时重传防丢包; 流量拥塞双控制,校验连接保可靠;

引导

滑动窗口算法;慢启动;拥塞控制;拥塞避免;快重传和快恢复;

最近流行的所谓的基于 UDP 的可靠传输,差不多也是靠这些机制。比如说 QUIC 协议也同样有序列号、确认应答、重传机制、流量控制、拥塞控制、快重传和快恢复这些机制。

简述

传输可靠性,做法都一样;

引导

QUIC;

TCP连接的两端,同一时间,双方都可以互相主动发送消息。这种就是所谓的全双工

而早期的HTTP/1.1,同一时间下客户端和服务端就只能一方发送数据,也就是基于TCP的HTTP协议把全双工给干废了,完成了半双工

这个主要是因为早期HTTP设计的时候,考虑的是看看网页文本的场景,能做到客户端发起请求再由服务器响应,就够了。而对于后面页游的出现,就需要这种客户端和服务端能互相发送大量消息的需求

所以为了支持这种场景,我们就需要另外一个基于TCP的协议

于是新的应用层协议websocket就被设计出来了。

浏览器在TCP三次握手建立连接后,都统一使用HTTP协议进行一次通信

如果此时是普通的HTTP请求,就还是老样子

如果想走websocket协议,就会在HTTP带上一些特殊的header,如果服务器正好支持升级为websocket,那就会走websocket握手流程

HTTP2,3均未实现 全双工通信

这个其实是先出现的RPC,然后才有的HTTP

在CS 架构上,客户端大多调用自家服务端的接口,这时候就可以用RPC

但在BS架构上,需要由浏览器调用各家公司的服务器,这时候就需要统一的标准协议,方便调用,就出现了HTTP

那为什么出现了HTTP后,不废除RPC呢

  1. 在公司内部,RPC调用内部接口比HTTP更加方便,不需要携带各种复杂的头,还有就是不需要考虑重定向之类的情况
  2. 基于历史原因,还是保留了RPC

CS 系统里,客户端和服务端通常由同一家公司开发和维护,他们可以完全控制协议格式。

浏览器和服务器都是由不同厂商、不同团队开发的,如果没有统一的通信协议,就会出现“这个浏览器只能访问某些网站”的情况。

加密概念

对称加密:使用相同的密钥进行加密解密,快,但密钥管理困难

非对称加密:使用公钥进行加密,使用私钥进行解密,安全性好,但是加解密比较慢

HTTPS使用 对称加密非对称加密的结合体

  • 通信建立前使用非对称加密交换会话密钥,即**证书验证阶段**后续就不在使用非对称加密
  • 在通信过程中全程使用对称加密的 会话加密 的方式加密明文数据

HTTP和HTTPS区别

HTTP是超文本传输协议,明文传输,安全性比较低

HTTPS 则解决HTTP不安全的缺陷,在TCP和HTTP之间加入了SSL/TLS安全协议,使得报文能加密传输

HTTP连接建立相对简单,三次握手后便可以进行HTTP报文的传输。而HTTPS则还需要进行SSL/TLS的握手过程。才可以进行加密报文的传输

两者的端口不一样,HTTP的默认端口是80,而HTTPS是443

HTTPS协议是需要向CA申请数字证书的,来保证服务器的身份是可信的,同时获取服务器公钥

CA证书验证过程

服务器将它的公钥等原始信息打包起来,用hash算法生成一个信息摘要,然后CA对这个信息摘要进行私钥加密,生成数字签名。 数字签名 = 私钥加密( hash(公钥) )

原始信息和数字签名一起打包进来,生成数字证书,然后由CA颁发给服务器

以上是服务端申请证书的流程,以下是客户端如何拿到证书

客户端请求服务端后,会拿到证书,然后通过证书的公钥解密数字签名,得到第一份信息摘要,然后通过hash算法对原始内容进行运算,得到第二份信息摘要,通过比较两份信息摘要,就可以知道这个数字证书可不可靠(因为是用公钥解密),且有没有被更改(因为更改的话,hash后的值就会变化)

证书内容:

过程:

数据传输过程

随机数加解密这个过程就是 非对称的

随机数就相当于密钥了,服务端和客户端都会存一份,且不会在网络中传输,也就不会被网络劫持拿到

代码模拟

HTTPS如何优化

协议优化:

spring4.x的组件图,5.x的变化在图中标注出来了

Spring 的核心容器是其他模块建立的基础,由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能。具体介绍如下。

  • Beans模块:提供了框架的基础模块,包括控制反转以及依赖注入
  • Core 核心模块:封装了Spring框架的底层部分,包括资源访问,类型装换等工具
  • Context:建立在 Core 和 Beans 模块的基础之上,集成 Beans 模块功能并添加资源绑定、数据验证、国际化、Java EE 支持、容器生命周期、事件传播等。ApplicationContext 接口是上下文模块的焦点
  • SpEl:提供了强大的表达式语言支持,支持访问和修改属性值,方法调用,支持访问及修改数组、容器和索引器,命名变量,支持算数和逻辑运算,支持从 Spring 容器获取 Bean,它也支持列表投影、选择和一般的列表聚合等。

SPEL日志的用例:
如何优雅地记录操作日志?

Data Access/Integration:

数据访问/集成层包括 JDBC、ORM、OXM、JMS 和 Transactions 模块,具体介绍如下。

  • JDBC 模块:提供了一个 JDBC 的样例模板,使用这些模板能消除传统冗长的 JDBC 编码还有必须的事务控制,而且能享受到 Spring 管理事务的好处。
  • ORM 模块:提供与流行的“对象-关系”映射框架无缝集成的 API,包括 JPA、JDO、Hibernate 和 MyBatis 等。而且还可以使用 Spring 事务管理,无需额外控制事务。
  • OXM 模块:提供了一个支持 Object /XML 映射的抽象层实现,如 JAXB、Castor、XMLBeans、JiBX 和 XStream。将 Java 对象映射成 XML 数据,或者将XML 数据映射成 Java 对象。
  • JMS 模块:指 Java 消息服务,提供一套 “消息生产者、消息消费者”模板用于更加简单的使用 JMS,JMS 用于用于在两个应用程序之间,或分布式系统中发送消息,进行异步通信。
  • Transactions 事务模块:支持编程和声明式事务管理。

Web:

Spring 的 Web 层包括 Web、Servlet、WebSocket 和 Webflux 组件,具体介绍如下。

  • Web 模块:提供了基本的 Web 开发集成特性,例如多文件上传功能、使用的 Servlet 监听器的 IOC 容器初始化以及 Web 应用上下文。
  • Servlet 模块:提供了一个 Spring MVC Web 框架实现。Spring MVC 框架提供了基于注解的请求资源注入、更简单的数据绑定、数据验证等及一套非常易用的 JSP 标签,完全无缝与 Spring 其他技术协作。
  • WebSocket 模块:提供了简单的接口,用户只要实现响应的接口就可以快速的搭建 WebSocket Server,从而实现双向通讯。
  • Webflux 模块: Spring WebFlux 是 Spring Framework 5.x中引入的新的响应式web框架。与Spring MVC不同,它不需要Servlet API,是完全异步且非阻塞的,并且通过Reactor项目实现了Reactive Streams规范。Spring WebFlux 用于创建基于事件循环执行模型的完全异步且非阻塞的应用程序。

此外Spring4.x中还有Portlet 模块,在Spring 5.x中已经移除

AOP、Aspects、Instrumentation和Messaging:

  • AOP 模块:提供了面向切面编程实现,提供比如日志记录、权限控制、性能统计等通用功能和业务逻辑分离的技术,并且能动态的把这些功能添加到需要的代码中,这样各司其职,降低业务逻辑和通用功能的耦合。
  • Aspects 模块:提供与 AspectJ 的集成,是一个功能强大且成熟的面向切面编程(AOP)框架。
  • Instrumentation 模块:提供了类工具的支持和类加载器的实现,可以在特定的应用服务器中使用。
  • messaging 模块:Spring 4.0 以后新增了消息(Spring-messaging)模块,该模块提供了对消息传递体系结构和协议的支持。
  • jcl 模块: Spring 5.x中新增了日志框架集成的模块。

Test:

Test 模块:Spring 支持 Junit 和 TestNG 测试框架,而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能。

  • 工厂模式,eg:ioc容器,BeanFactory
  • 单例模式,eg:ioc容器
  • 适配器,eg:Springmvc那一套,HandlerAdpter用适配器去适配不同的Controller
  • 责任链,eg:过滤器那里
  • 代理设计模式,eg:Spring AOP功能的实现
  • 观察者,eg:Spring的事件发布模式
  • 装饰者模式,eg: 我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 说白了就是把那几个不同的数据库包装起来
  • 模版方法,eg:Spring中的RedisTemplate,jdbcTemplate等以Template方法结尾的类,都用到了模版方法

构造器: 通过构造方法创建Bean(@Compoent就是这种方式)

静态工厂: 一个静态方法返回Bean,声明这个静态方法,例如@Bean或xml配置文件,工厂需要@Configuration

工厂方法: 工厂继承FactoryBean<>接口,指定泛型,即需要创建的Bean,声明这个工厂

实例工厂: 和静态工厂类似,方法不需要是静态的(@Bean就是这种方式)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Configuration
public class AppConfig {

// 1. 构造器方式
@Bean
public UserService userServiceByConstructor() {
return new UserService();
}

// 2. 静态工厂方式
@Bean
public UserService userServiceByStaticFactory() {
return UserFactory.createStaticUserService();
}

// 3. 实例工厂方式
@Bean
public UserFactory userFactory() {
return new UserFactory();
}

@Bean
public UserService userServiceByInstanceFactory(UserFactory userFactory) {
return userFactory.createInstanceUserService();
}

// 4. FactoryBean 方式
@Bean
public UserServiceFactoryBean userServiceByFactoryBean() {
return new UserServiceFactoryBean();
}
}


  1. 实例化Bean(通过BeanDefination反射调用无参构造方法创建实例,如果没有,则需要在构造方法上添加@Autowird)
  2. 给bean的属性set赋值
  3. 检查Bean是否实现了Aware相关接口,实现的话就执行方法
    Aware接口:空接口,有子类接口,子类接口有方法,方法作用见名知意:

BeanNameAware:void setBeanName(String name);

BeanFactoryAware:void setBeanFactory(BeanFactory beanFactory) throws BeansException;

ApplicationContextAware: void setApplicationContext(ApplicationContext applicationContext);

BeanClassLoaderAware:void setBeanClassLoader(ClassLoader classLoader);

  1. 执行BeanPostProcessor(Bean后处理器)的before方法,此时返回的Bean可以被偷梁换柱
    • “偷梁换柱” = 在 postProcessBeforeInitialization 里用一个新对象替换原 Bean
    • 主要用途:
      • AOP 代理(Spring 里所有基于代理的增强其实就是这么干的)
      • 装饰模式增强 Bean
      • 做一些动态替换/包装
  2. 检查Bean是否实现了InitializingBean接口,如果实现了,那就执行里面的afterPropertiesSet()方法
  3. 初始化Bean, —- 配置文件中的init-method方法或者注解的@Bean(initMethod=”init”) (两者其一)
  4. 执行BeanProcessor的after方法,此时返回的Bean可以被偷梁换柱,AOP此时在这杯发现
  5. 使用Bean
  6. 销毁Bean,检查Bean是否实现了DisposableBean接口,实现的话执行里面的destroy方法
  7. 销毁Bean,配置文件中的destroy-method方法或者方法注解上的@Bean(destroyMethod = “destroyMethod”)(二者其一,看使用配置文件还是注解)

注意点:

  • 销毁Bean是在容器关闭前进行的销毁
    容器关闭 = Spring 应用停止/销毁时,Spring 容器会结束 Bean 的管理。
  • 如果出现了@PostContruct和@PreDestroy(两个JDK注解,则会分别穿插在第四步和第八步之后)

大致就是分为五个阶段

实例化:步骤一

依赖注入:步骤二

初始化:步骤三到七

使用:步骤八

销毁:步骤九到十

为什么初始化要有那么多步骤,每个步骤干了什么事?

灵活性:不同的步骤提供了不同的挂钩点,允许开发者在不同阶段进行介入

扩展性:通过实现不同的Aware和PostProcessor接口,开发者可以扩展Bean的功能,增强与容器的交互能力

分离关注点:每个步骤专注于特定的任务,使得初始化过程更加清晰和可维护。

安全:确保Bean在被使用前经过充分的验证和准备

BeanNameAware.setBeanName()

作用:将Bean的名称传递给Bean实例。

用途:在Bean中需要知道自身名称时使用,方便在运行时进行标识或日志记录。

BeanFactoryAware.setBeanFactory()

作用:将当前BeanFactory实例传递给Bean。

用途:允许Bean访问其创建工厂,从而可以调用工厂的其他Bean或获取配置信息。

ApplicationContextAware.setApplicationContext()

作用:将当前的ApplicationContext实例传递给Bean。

用途:使Bean可以与Spring的应用上下文进行交互,获取上下文中的资源或其他Bean。

BeanPostProcessor.postProcessBeforeInitialization()

作用:在Bean初始化之前执行自定义逻辑。

用途:允许在Bean的依赖注入完成后但初始化方法调用前,对Bean进行额外处理,如修改属性或包装Bean实例。

InitializingBean.afterPropertiesSet()

作用:在Bean属性设置完成后进行初始化。

用途:提供了一个在所有属性设置完成后执行初始化逻辑的机会,通常用于配置验证或初始化某些资源。

自定义init-method方法

作用:调用用户在配置中指定的初始化方法。

用途:允许开发者通过配置文件指定一个自定义的初始化方法,以执行特定的初始化逻辑。

BeanPostProcessor.postProcessAfterInitialization()

作用:在Bean初始化之后执行自定义逻辑。

用途:允许在Bean完成初始化后进行最终的处理,如代理增强或其他后处理逻辑。

这个得看情况,如果你一个Service接口,然后有三个实现类Service1,2,3。那么这时候这个Service类型的Bean就不是单例了,但对于Service1就是单例的。

如果说单例Bean是单例模式,则它的范围是名字范围,而不是类型范围,就是同个名字下的Bean就是单例的,如果是同个类型下就不是了。