Android应用集成RabbitMQ消息处理指南

Android应用集成RabbitMQ消息处理指南

    • RabbitMQ
    • 1、前言
    • 2、RabbitMQ简介
      • 2.1、什么是RabbitMQ
      • 2.2、RabbitMQ的特点
      • 2.3、RabbitMQ的工作原理
      • 2.4、RabbitMQ中几个重要的概念
    • 3、在Android Studio中集成RabbitMQ
      • 3.1、在Manifest中添加权限:
      • 3.2、在build.gradle(:app)下添加依赖:
    • 4、建立连接
      • 4.1、创建ConnectionFactory对象
      • 4.2、使用ConnectionFactory创建连接
      • 4.3、创建Channel
      • 4.4、声明队列、交换机等
      • 4.5、生产或消费消息
      • 4.6、关闭连接
    • 5、发送消息
      • 5.1、创建连接和通道
      • 5.2、声明队列
      • 5.3、准备消息内容
      • 5.4、发布消息
      • 5.5、关闭资源
      • 5.6、案例
    • 6、接收消息
      • 6.1、创建连接和通道
      • 6.2、声明队列
      • 6.3、定义消费者
      • 6.4、监听队列
      • 6.5、接收消息
      • 6.6、确认消息
      • 6.7、关闭资源
      • 6.8、案例
    • 7、确认机制
      • RabbitMQ中的确认机制主要分为两种:
        • 7.1、发布确认(Publisher Confirms)
        • 7.2、消费者确认(Consumer Acknowledgments)
    • 8、确认主题
      • RabbitMQ有几种常见的主题类型,选择使用哪一种主要根据具体的应用场景:
        • 8.1、Direct exchange(默认)
        • 8.2、Fanout exchange
        • 8.3、Topic exchange
        • 8.4、Headers exchange
      • 选择使用哪种主题类型,主要根据实际的业务需求来判断:
    • 9、使用示例
      • RabbitMQ在Android、IOS、小程序等多端应用中典型应用场景和作用:
        • 9.1、异步处理
        • 9.2、推送通知
        • 9.3、数据传输
        • 9.4、负载均衡
        • 9.5、流量削峰
        • 9.6、服务解耦
        • 9.7、弹性扩容
        • 9.8、离线操作支持
      • 实际应用:
        • 效果展示
        • 具体实现
    • 10、总结

RabbitMQ

RabbitMQ官网直通车 —> ✈✈✈✈✈✈

1、前言

       最近工作繁忙,好久没有更新博文了。

       对于互联网饱和的今天,如何做到不同系统之间传递信息与通信?在实际项目中,多个端例如:ios、android、pc、小程序采用从RabbitMQ上获取实时包消息,然后根据此实时包消息来做响应处理。

       随着互联网技术的发展,系统之间的耦合度越来越高。为了实现系统间的解耦,消息中间件应运而生。其中作为一款优秀的开源消息中间件,RabbitMQ凭借其易用、高可靠、多协议支持等特性,被广泛应用于异步处理、任务队列等领域,成为实际项目的首选。

       但是对于许多人来说,RabbitMQ还是比较陌生的。概念多、不知如何上手使用,这成为很多人学习和使用RabbitMQ的障碍。接下来,给大家介绍关于RabbitMQ的内容。

2、RabbitMQ简介

2.1、什么是RabbitMQ

       MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。其中较为成熟的MQ产品有IBM WEBSPHERE MQ等等。

RabbitMQ是采用Erlang语言实现的开源消息队列系统,是当前最主流的消息中间件之一。

通俗来讲的话,RabbitMQ就像是一个邮局,负责接收和转发信件。

  • 生产者就像邮寄的客户,把信件(消息)投递到RabbitMQ邮局。
  • 消费者就像收信人,从RabbitMQ邮局取走并处理信件。
  • RabbitMQ保证每封信件(消息)都会安全可靠地到达收信人(消费者),它不会丢失或者重复发送信件。
  • RabbitMQ可以给不同的收信人(消费者)分发同一封信件的复印件,这样多个收信人可以并行处理信件。
  • 如果RabbitMQ邮局堆积太多信件来不及处理,它会把信件排队,先进先出依次发送。
  • RabbitMQ还可以给特殊的信件设置优先级,让重要的信件优先处理。
  • RabbitMQ可以根据收信人的处理能力分发信件,不会让一个收信人处理过多信件。

所以简单来说,RabbitMQ就是一个智能的邮局系统,保证每个消息都被安全可靠地发送和处理。它非常适合用于不同系统之间传递消息与通信。

2.2、RabbitMQ的特点

  • 支持多种消息协议,包括STOMP、MQTT等。
  • 支持消息队列,可以缓存消息。
  • 支持消息持久化,防止消息丢失。
  • 支持复杂的路由规则,可以实现发布-订阅、负载均衡等功能。
  • 高可靠性,支持集群模式。
  • 管理界面友好,使用方便。

2.3、RabbitMQ的工作原理

  • 生产者(Publisher)生成消息并发布到RabbitMQ服务器。
  • 消费者(Consumer)从RabbitMQ服务器拉取消息并进行处理。
  • RabbitMQ充当了一个消息代理(Message Broker)的角色,负责接收、存储和转发消息。

2.4、RabbitMQ中几个重要的概念

  • Producer(生产者):发送消息的应用程序是Producer。Producer将消息发布到RabbitMQ中去。
  • Consumer(消费者):接收消息的应用程序是Consumer。Consumer从RabbitMQ中获取消息进行处理。
  • ConnectionFactory(工厂类):它是是RabbitMQ Java客户端用于创建连接的工厂类。它封装了用于创建连接的所有参数配置。
  • Exchange(交换机):交换机用于接收生产者发送的消息,并根据路由键将消息路由到指定的队列中。
  • Queue(消息队列):消息队列是RabbitMQ内部存储消息的缓冲区。Producer发送的消息会先存储在Queue中,Consumer从Queue中获取消息进行处理。
  • Channel(通道):进行消息读写的通道,它是建立在Connection上的一个虚拟连接。为了实现并发,同时方便业务和异常隔离,最佳实践是基于单个Connection建立多个Channel,而不是直接基于Connection操作。
  • Routing Key(路由键):生产者将消息发布到Exchange时,会指定一个Routing Key。Exchange根据这个Routing Key决定将消息路由到哪个队列。
  • Binding(绑定):绑定是Exchange和Queue之间的关联关系。绑定中可以包含routing key。
  • Virtual host(虚拟主机):RabbitMQ可以创建多个虚拟主机,用于进行权限管理和进行逻辑隔离。
  • Message Acknowledgment (消息确认):消费者可以启用消息确认机制,在收到消息并处理后发送确认回执给RabbitMQ,RabbitMQ才会将消息从Queue中移除。

3、在Android Studio中集成RabbitMQ

3.1、在Manifest中添加权限:

<uses-permission android:name="android.permission.INTERNET" />

3.2、在build.gradle(:app)下添加依赖:

implementation 'com.rabbitmq:amqp-client:5.19.0'

耐心等待as同步完成后,就可以使用RabbitMQ的相关api了。

4、建立连接

4.1、创建ConnectionFactory对象

这个对象包含了创建连接需要的配置,比如RabbitMQ主机地址,端口,虚拟主机,用户名密码等。

ConnectionFactory factory = new ConnectionFactory();
// 连接配置
// factory.setHost(Config.MQ_ADDRESS); // 服务器ip
// factory.setPort(Integer.parseInt(Config.MQ_PORT)); // 端口
// factory.setUsername(Config.MQ_USERNAME); // 用户名
// factory.setPassword(Config.MQ_PASSWORD); // 密码
// factory.setVirtualHost(Config.MQ_VIRTUALHOST);
factory.setUri(url);

4.2、使用ConnectionFactory创建连接

调用ConnectionFactory的createConnection()方法可以创建一个连接对象。

Connection connection = factory.newConnection();

4.3、创建Channel

在连接上创建一个通道,用于进行消息发布或者消费。

Channel channel = connection.createChannel();

4.4、声明队列、交换机等

使用channel进行队列、交换机等的声明。

4.5、生产或消费消息

通过channel发送或接收消息。

4.6、关闭连接

使用完成后关闭连接和channel。

channel.close();
connection.close();

5、发送消息

5.1、创建连接和通道

使用ConnectionFactory创建连接,然后在连接上创建通道。

5.2、声明队列

如果队列不存在,需要提前声明队列。

5.3、准备消息内容

定义要发送的消息内容体,可以是字节数组或字符串等。

5.4、发布消息

使用通道对象调用basicPublish方法,它需要exchange名称,routing key和消息内容。

5.5、关闭资源

发送完成后可以关闭通道和连接。

5.6、案例

// 构建消息内容
String message = "Hello World!";// 发布消息到队列
channel.basicPublish(EXCHANGE_NAME, "routingkey", null, message.getBytes());// 关闭资源
channel.close();
connection.close();

6、接收消息

6.1、创建连接和通道

使用ConnectionFactory创建连接,然后在连接上创建通道。

6.2、声明队列

如果队列不存在则需要先声明队列。

6.3、定义消费者

实现Consumer接口,定义消息处理逻辑。

6.4、监听队列

使用通道对象调用basicConsume方法,监听指定队列。

6.5、接收消息

RabbitMQ将向Consumer递送消息,在handleDelivery方法中可以获取消息并处理。

6.6、确认消息

处理完成后,调用channel的basicAck方法手动确认消息。

6.7、关闭资源

最后需要关闭通道和连接。

6.8、案例

channel.basicConsume(QUEUE_NAME, true, consumer); public class MyConsumer implements Consumer {public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) {// 获取消息并处理String message = new String(body, "UTF-8");System.out.println("Received message: " + message);// 确认消息channel.basicAck(envelope.getDeliveryTag(), false);}
}

7、确认机制

RabbitMQ中的确认机制主要分为两种:

7.1、发布确认(Publisher Confirms)

这是一种单向确认机制,允许生产者知道消息是否被 RabbitMQ 接收。

在 Channel 上启用确认模式后,所有的消息都会被指派一个唯一的 ID(从 1 开始),一旦消息被投递到所有匹配的队列后,RabbitMQ 就会发送一个确认给生产者(包含消息的唯一 ID),这就使得生产者知道消息已经被处理了。

如果消息和队列是可持久化的,那么确认机制本身对消息持久化也是必要的。


在 Java 客户端中,可以通过 Channel 的 confirmSelect 方法将 Channel 设置为确认模式:

channel.confirmSelect();

之后可以添加监听器监听确认和未确认的消息:

channel.addConfirmListener(new ConfirmListener(){// ...
});
7.2、消费者确认(Consumer Acknowledgments)

这是一种双向确认机制,不仅可以告诉生产者消息已送达,也可以告诉 RabbitMQ 消息已经被消费者接收并处理完毕。

开启确认模式后,消息一旦被消费者接收,就会从 RabbitMQ 的消息缓冲区中移除。如果消费者在处理消息时发生故障或者异常退出,未处理完毕的消息就会被 RabbitMQ 重新派发给其他消费者,以此来确保消息不会丢失。

通过正确使用确认机制,既可以提高 RabbitMQ 的性能和消息处理能力,也可以确保业务流程的完整性。所以在实际使用中,确认机制是非常重要的。


在 Java 客户端中,可以在 basicConsume 时设置autoAck=false,之后手动调用 basicAck 实现确认:

channel.basicConsume(queue, false, consumer); consumer.handleDelivery(envelope, properties, body) {//...channel.basicAck(envelope.getDeliveryTag(), false); 
}

8、确认主题

RabbitMQ有几种常见的主题类型,选择使用哪一种主要根据具体的应用场景:

8.1、Direct exchange(默认)

直接交换机,按照routing key完全匹配分发消息到队列。场景是需要指定的队列接收消息。

8.2、Fanout exchange

扇出交换机,会将消息分发到所有绑定的队列。场景是需要广播消息。

8.3、Topic exchange

主题交换机,按照routing key的规则匹配分发消息到队列。场景是需要根据规则分发消息到不同队列。

8.4、Headers exchange

头交换机,按照发送消息的headers属性进行匹配分发消息。场景是需要根据消息头进行路由分发。

选择使用哪种主题类型,主要根据实际的业务需求来判断:

  • 如果需要直接将消息发送到指定的队列,使用direct交换机。
  • 如果需要广播消息到所有队列,使用fanout交换机。
  • 如果需要基于规则匹配分发消息,使用topic交换机。
  • 如果需要根据消息头属性进行分发,使用headers交换机。

在代码中,声明交换机时指定类型即可,如下:

channel.exchangeDeclare("myExchange","topic");

9、使用示例

RabbitMQ在Android、IOS、小程序等多端应用中典型应用场景和作用:

9.1、异步处理

各端可以通过RabbitMQ实现任务的异步处理,避免用户等待,提升用户体验。比如小程序下单后,通过RabbitMQ异步把订单信息发送给服务器。

9.2、推送通知

可以通过RabbitMQ实现移动端的消息推送通知,如订单发货通知等。

9.3、数据传输

移动端和服务器端可以通过RabbitMQ进行数据的传输,避免直接耦合,提高传输灵活性。

9.4、负载均衡

RabbitMQ可以在多端和服务器之间进行负载均衡,防止服务器压力过大。

9.5、流量削峰

使用RabbitMQ的消息队列处理请求峰值,防止服务器被瞬时压垮。

9.6、服务解耦

不同端只依赖RabbitMQ进行通信,不需要关注对方技术实现细节,实现服务解耦。

9.7、弹性扩容

通过RabbitMQ可以方便各端与服务器的弹性扩容。

9.8、离线操作支持

移动端可以通过RabbitMQ实现某些离线操作,待网络恢复后再同步到服务器。

实际应用:

       本人在实际物联网项目中,用户通过无线设备测量身体指标后,设备通过网络把数据给到后台;后台通过解析数据后,通过MQ把数据给到每个端,通过收到的信息包各个端做相应的处理。

本人使用ConnectionFactory在创建连接需要配置的时候,通过配置Url来建立连接等。通过startConsumer开始消费并监听指定队列,然后定义回调接口DeliverCallback来接收信息包。最终通过EventBus来传递数据信息包。

效果展示

在这里插入图片描述
在这里插入图片描述

具体实现

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/473682e32d2a48fabd1efa6bba256e84.png

/*** @author 拉莫帅* @date 2023/10/24* @address* @Desc EventBus*/
public class MessageEvent {private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}
}
/*** @author 拉莫帅* @date 2023/10/24* @address* @Desc rabbitMQ*/
public class RabbitMQUtil {private Connection connection;private Channel channel;private ConnectionFactory factory;private String queueName;public RabbitMQUtil(String httpType, String userName, String password, String host, String port, String virtualHost, String exChangeName, String bindingKey) {new Thread(new Runnable() {@Overridepublic void run() {if (connection == null) {// 创建一个连接factory = new ConnectionFactory();try {StringBuilder builder = new StringBuilder();StringBuilder stringBuilder = builder.append(httpType).append("://").append(userName).append(":").append(password).append("@").append(host).append(":").append(port).append("/").append(virtualHost);String url = stringBuilder.toString();Log.e("RabbitMQ", "Url " + url);// 连接配置// factory.setHost(Config.MQ_ADDRESS); // 服务器ip// factory.setPort(Integer.parseInt(Config.MQ_PORT)); // 端口// factory.setUsername(Config.MQ_USERNAME); // 用户名// factory.setPassword(Config.MQ_PASSWORD); // 密码// factory.setVirtualHost(Config.MQ_VIRTUALHOST);factory.setUri(url);// 创建一个新的代理连接connection = factory.newConnection();// 使用内部分配的通道号创建一个新通道channel = connection.createChannel();channel.exchangeDeclare(exChangeName, "topic", true); // 声明一个转发器queueName = channel.queueDeclare().getQueue();channel.queueBind(queueName, exChangeName, bindingKey); // 绑定一个到转发器Log.e("Waiting for logs.", "");startConsumer();} catch (URISyntaxException e) {e.printStackTrace();} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (KeyManagementException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}}}}).start();}/*** 开始消费*/public void startConsumer() throws Exception {Log.e("startConsumer", "");// 定义回调接口DeliverCallbackDeliverCallback callback = (consumerTag, message) -> {String result = new String(message.getBody(), "UTF-8");Log.e("DeliverCallback >>>", result);// 创建一个事件MessageEvent event = new MessageEvent();event.setMessage(result);// 通过EventBus发送事件EventBus.getDefault().post(event);};// 启动基本消费,并传入回调接口channel.basicConsume(queueName, true, callback, consumerTag -> {});}/*** 关闭连接*/public void close() throws Exception {channel.close();connection.close();}
}
public class MainActivity extends AppCompatActivity {private static final String bindingKey = "topic.chain=2.region=3.area=4.pharmacy=5.";private RabbitMQUtil rabbitMQUtil;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initMQ();}private void initMQ() {if (rabbitMQUtil == null) {rabbitMQUtil = new RabbitMQUtil(Config.MQ_HTTP_TYPE, Config.MQ_USERNAME, Config.MQ_PASSWORD,Config.MQ_ADDRESS, Config.MQ_PORT, Config.MQ_VIRTUALHOST, Config.MQ_EXCHANGE, bindingKey);}}@Overridepublic void onStart() {super.onStart();EventBus.getDefault().register(this);}@Overridepublic void onStop() {super.onStop();EventBus.getDefault().unregister(this);}// 接收事件@Subscribe(threadMode = ThreadMode.MAIN)public void onMessage(MessageEvent event) {String message = event.getMessage();Log.e("接收MQ +++++++++++++", message);// 更新UI// ...}@Overrideprotected void onDestroy() {super.onDestroy();new Thread(new Runnable() {@Overridepublic void run() {try {rabbitMQUtil.close();} catch (Exception e) {e.printStackTrace();}}}).start();}
}

10、总结

RabbitMQ优秀的性能和灵活性,使其可以处理从简单的请求-响应交互到复杂的异步处理场景

既可以用于系统间的异步解耦,也可以实现应用内不同组件的解耦。它非常适合用于分布式系统之间的数据交换与集成,已成为企业级分布式架构的重要组件之一。

总体来说,RabbitMQ作为一款易用、稳定、功能强大的消息中间件,可以提供高可用、可扩展、低时延的消息服务,在实际项目中使用广泛。并且在当前的技术栈中占有非常重要的地位,是必须要掌握的技能之一。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/180274.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广告引擎检索技术快速学习

目录 一、广告系统与广告引擎介绍 &#xff08;一&#xff09;广告系统与广告粗分 &#xff08;二&#xff09;广告引擎在广告系统中的重要性分析 二、广告引擎整体架构和工作过程 &#xff08;一&#xff09;一般概述 &#xff08;二&#xff09;核心功能架构图 三、标…

2023年【起重机司机(限桥式起重机)】报名考试及起重机司机(限桥式起重机)模拟考试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 起重机司机(限桥式起重机)报名考试参考答案及起重机司机(限桥式起重机)考试试题解析是安全生产模拟考试一点通题库老师及起重机司机(限桥式起重机)操作证已考过的学员汇总&#xff0c;相对有效帮助起重机司机(限桥式起…

基于PHP + MySQL实现的文章内容管理系统源码+数据库,采用前后端分离的模板和标签化方式

文章内容管理系统 dc-article是一个通用的文章内容管理系统&#xff0c;基于开源的caozha-admin开发&#xff0c;采用前后端分离的模板和标签化方式&#xff0c;支持文章内容管理、栏目分类管理、评论管理、友情链接管理、碎片管理、远程图片获取器等功能。可以使用本系统很轻…

Go Gin中间件

Gin是一个用Go语言编写的Web框架&#xff0c;它提供了一种简单的方式来创建HTTP路由和处理HTTP请求。中间件是Gin框架中的一个重要概念&#xff0c;它可以用来处理HTTP请求和响应&#xff0c;或者在处理请求之前和之后执行一些操作。 以下是关于Gin中间件开发的一些基本信息&am…

WorkManger学习汇总

一.使用 WorkManger主要是用来执行一定会执行的任务的&#xff0c;如即使app被杀掉、手机重启都会执行。 适用场景&#xff1a;定期重复性任务&#xff0c;如定期log上传等 使用的话首先引入库&#xff08;我使用的是2.7.1&#xff09; implementation "androidx.work:…

2015年亚太杯APMCM数学建模大赛C题识别网络中的错误连接求解全过程文档及程序

2015年亚太杯APMCM数学建模大赛 C题 识别网络中的错误连接 原题再现 网络是描述真实系统结构的强大工具——社交网络描述人与人之间的关系&#xff0c;万维网描述网页之间的超链接关系。随着现代技术的发展&#xff0c;我们积累了越来越多的网络数据&#xff0c;但这些数据部…

0.专栏概述与几句闲话

引 还记得今年大年初一开始写《数据结构和算法》专栏的时候定了个小目标&#xff1a; 不知不觉间已经过去了十个月&#xff0c;我的第一个专栏也算是圆满收官了 。 这次PO一张成都熊猫基地的团子们&#xff0c;开启设计模式这个专栏吧。 目录与概述 犹记得一位身在广州的老…

php语言

文章目录 常用命令Apache命令php命令 常用命令 Apache命令 查看版本号 D:\cjm\soft-work\phpStudy\phpstudy_pro\Extensions\Apache2.4.39\bin>httpd -v检测运行环境 httpd -tphp命令 PHP版本号 需要进入php目录 php -v

一文搞懂设计模式之七大原则

大家好&#xff0c;我是晴天。在接下来的一个多月里&#xff0c;我将跟大家一起学习设计模式的一些基础知识和基本应用。不要问我为什么突然想起来写一个设计模式系列的文章&#xff0c;问就是&#xff1a;爱过。。。 问题引出 作为程序猿的我们&#xff0c;隔三岔五的就会因为…

Azure 机器学习 - 无代码自动机器学习的预测需求

了解如何在 Azure 机器学习工作室中使用自动化机器学习在不编写任何代码行的情况下创建时序预测模型。 此模型将预测自行车共享服务的租赁需求。 关注TechLead&#xff0c;分享AI全维度知识。作者拥有10年互联网服务架构、AI产品研发经验、团队管理经验&#xff0c;同济本复旦硕…

牛客项目(五)-使用kafka实现发送系统通知

kafka入门以及与spring整合 Message.java import java.util.Date;public class Message {private int id;private int fromId;private int toId;private String conversationId;private String content;private int status;private Date createTime;public int getId() {retur…

Marp: 将 Markdown 变为 PPT 式样的 VScode 插件

样例代码&#xff1a; --- marp: true size: 16:9 theme: default header: footer: --- <!-- _footer: Jia ming<br>Gansu University of Political Science and Law --> <!-- _backgroundColor: lightskyblue --> ## <!-- fit --> 笔记检验概述>…

pytorch 中 nn.Conv2d 解释

1. pytorch nn.Con2d 中填充模式 torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride1, padding0, dilation1, groups1, biasTrue, padding_mode‘zeros’, deviceNone, dtypeNone) 1.1 padding 参数的含义 首先 &#xff0c;padd N, 代表的是 分别在 上下&…

鉴源实验室 | 自动驾驶传感器攻击研究

作者 | 付海涛 上海控安可信软件创新研究院汽车网络安全组 来源 | 鉴源实验室 社群 | 添加微信号“TICPShanghai”加入“上海控安51fusa安全社区” 01 自动驾驶汽车的脆弱性 自2015年以来&#xff0c;汽车的信息安全问题受到国内外的广泛关注。而随着汽车的智能化与网联化的…

上海物理、化学高考命题趋势及2024年上海物理、化学高考备考建议

在上海高考时&#xff0c;物理、化学虽然不像语文、英语和数学那样分数高&#xff0c;但是仍然很重要。那么&#xff0c;从这几年的上海物理、化学的高考题目来看&#xff0c;我们互发现什么命题趋势和考题特点呢&#xff1f;如何备考接下来的2024年高考物理和化学呢&#xff1…

Ubuntu下安装vscode,并解决终端打不开vscode的问题

Visual Studio Code安装 1&#xff0c;使用 apt 安装 Visual Studio Code 在官方的微软 Apt 源仓库中可用。按照下面的步骤进行即可&#xff1a; 以 sudo 用户身份运行下面的命令&#xff0c;更新软件包索引&#xff0c;并且安装依赖软件&#xff1a; sudo apt update sud…

uniapp 微信小程ios端键盘弹起后导致页面无法滚动

项目业务逻辑和出现的问题整理 新增页面 用户可以主动添加输入文本框 添加多了就会导致当前页面出现滚动条,这就导致ios端滚动页面的时候去点击输入框键盘抬起再关闭的时候去滚动页面发现页面滚动不了(偶尔出现),经过多次测试发现是键盘抬起的时候 主动向上滑动 100%出现这种问…

【Linux】进程的概念

文章目录 1. 基本概念2. 进程的描述3. 进程的一些基本操作3.1 查看进程3.2 结束进程3.3 通过系统调用获取进程标示符3.4 通过系统调用来创建子进程 4. 进程状态4.1 操作系统的进程状态4.2 Linux对于这些状态的处理方式 1. 基本概念 什么是进程&#xff1f; 在回答这个问题之前…

云安全—docker Deamon攻击面

0x00 前言 本篇文章主要是讲docker Deamon的原理以及docker Deamon攻击面相关的内容&#xff0c;属于抛砖引玉系列&#xff0c;如有不妥之处还请斧正。 0x01 docker Deamon 还是先来看一下docker Deamon的一些相关知识&#xff0c;依旧是采用问答的方式来进行。为了文章的整…

2023-11-04:用go语言,如果n = 1,打印 1*** 如果n = 2,打印 1*** 3*** 2*** 如果n = 3,打印

2023-11-04&#xff1a;用go语言&#xff0c;如果n 1&#xff0c;打印 1*** 如果n 2&#xff0c;打印 1***3*** 2*** 如果n 3&#xff0c;打印 1***3*** 2***4*** 5*** 6*** 如果n 4&#xff0c;打印 1***3*** 2***4*** 5*** 6***10** 9*** 8*** 7*** 输入…