当前位置: 首页 > news >正文

上海网站建设培训静态网站 挂马

上海网站建设培训,静态网站 挂马,江苏建设人才网查询,新网 网站空间目录 一. 前言 二. JMS 规范 2.1. 基本概念 2.2. JMS 体系结构 三. ActiveMQ 使用 3.1. ActiveMQ Classic 和 ActiveMQ Artemis 3.2. Queue 模式#xff08;P2P#xff09; 3.3. Topic 模式#xff08;Pub/Sub#xff09; 3.4. 持久订阅 3.5. 消息传递的可靠性 …目录 一. 前言 二. JMS 规范 2.1. 基本概念 2.2. JMS 体系结构 三. ActiveMQ 使用 3.1. ActiveMQ Classic 和 ActiveMQ Artemis 3.2. Queue 模式P2P 3.3. Topic 模式Pub/Sub 3.4. 持久订阅 3.5. 消息传递的可靠性 3.5.1. 事务型会话与非事务型会话 3.5.2. 持久化与非持久化消息的存储策略 3.6. 消息发送策略 3.7. Failover 参数配置 四. 原理解析 4.1. 生产消息原理 4.2. 消费消息原理 4.3. 消息确认及消息重发 五. 基本优化 六. 总结 一. 前言 一开始消息中间件的厂商繁多且各个厂商之间没有统一的规范这就导致了各消息中间件非常难以整合协作因此后来陆续出现了如 JMS 和 AMQP 这样的消息队列规范提供了统一的标准而 ActiveMQ 就是完全遵循 JMS 规范开发的消息队列。 二. JMS 规范 2.1. 基本概念 什么是 JMSJava Message Service规范JMS 是一个基于 Java 平台面向消息中间件MOM的 API用于在两个应用程序之间或分布式系统中发送消息进行异步通信。在设计JMS 时设计师就计划能够结合现有消息队列的优点如 不同的消息传送模式或域例如点对点消息传送和发布/订阅消息传送支持同步和异步消息支持可靠性消息的传输支持常见的消息格式如文本、字节、流、对象等。 2.2. JMS 体系结构 上图是对 JMS 的总体介绍下面对其中各个对象分别进行说明 1. ConnectionFactory连接工厂一般设为单例模式一旦创建就一直运行在应用容器内客户端使用连接工厂创建一个JMS连接。2. ConnectionJMS 连接表示 JMS 客户端和服务器端之间的一个活动的连接。3. SessionJMS 会话表示 JMS 客户端与 JMS 服务器端之间的会话状态。JMS 会话建立在JMS 连接上表示客户与服务器之间的一个会话线程。4. Destination消息管道从生产端流向客户端包括队列PTP主题Pub/Sub。5. Message Producer 和 Message Consumer生产者和消费者对象由 Session 对象创建用于发送和接收消息。6. MessageJMS 消息由以下几部分组成消息头属性消息体。 消息头HeaderJMS 消息头包含了许多字段它们是消息发送后由 JMS 提供者或消息发送者产生用来表示消息、设置优先权和失效时间等等并且为消息确定路由 Routing。属性Property由消息发送者产生用来添加删除消息头以外的附加信息。消息体Body由消息发送者产生JMS 中定义了5种消息体ByteMessage、MapMessage、ObjectMessage、StreamMessage 和 TextMessage。 三. ActiveMQ 使用 ActiveMQ 支持 P2P点对点传输和 Pub/Sub 模型这两种传递方式的本质区别就是消息是否可重复消费。比如微信私聊和群聊私聊就是 P2P除了私聊的双方其它人无法再获取消息而群聊就相当于 Pub/Sub 模式即群成员都订阅了该群的消息。 在讲消息传输之前我们先看看 ActiveMQ 官网发布的两种版本的区别。 3.1. ActiveMQ Classic 和 ActiveMQ Artemis ActiveMQ Classic 官网地址https://activemq.apache.org/components/classic/ ActiveMQ Artemis 官网地址https://activemq.apache.org/components/artemis/ 实际上 ActiveMQ Classic 原来就叫 ActiveMQ是 Apache 开发的基于 JMS 1.1 的消息服务器目前稳定版本号是 6.x而 ActiveMQ Artemis 是由 RedHat 捐赠的 HornetQ 服务器代码的基础上开发的目前稳定版本号是 2.x。 和 ActiveMQ Classic 相比Artemis 版的代码与 Classic 完全不同并且它支持JMS 2.0使用基于 Netty 的异步 IO大大提升了性能。针对数据的持久层 ActiveMQ Artemis 还能够支持 JDBC。 整体来说ActiveMQ 通常指的是 ActiveMQ Classic为了简化去掉了 Classic。ActiveMQ Artemis 应该是作为下一个版本来候选的支持的协议更新。2 套 ActiveMQ 的代码是不一样的。如果用不到什么太多的消息策略高级需求使用 ActiveMQ Classic 就好。因为这 2 个消息服务器的代码完全不一样导致如果你使用 Spring 的话使用的包的代码也不一样ActiveMQ Artems 的调用代码更加简单界面更好看。 3.2. Queue 模式P2P 先创建一个 Producer 生产消息 public static void main(String[] args) {ConnectionFactory factory new ActiveMQConnectionFactory(tcp://192.168.0.106:61616);Connection connection null;try {// 创建并开启连接connection factory.createConnection();connection.start();// 创建会话设置是否为事务型会话以及消息签收方式Session session connection.createSession(true, Session.AUTO_ACKNOWLEDGE);// 创建发送队列Destination destination session.createQueue(queue);// 创建消息发送者MessageProducer producer session.createProducer(destination);// 创建消息并设置消息内容TextMessage textMessage session.createTextMessage();textMessage.setText(Hello);// 发送消息producer.send(textMessage);session.commit();session.close();} catch (JMSException e) {e.printStackTrace();} finally {try {connection.close();} catch (JMSException e) {e.printStackTrace();}} } 上面代码注释写的很清楚了可以看到是完全符合 JMS 的体系结构的首先创建一个连接工厂并通过连接工厂创建连接然后通过连接创建会话在创建会话时可以指定是否为事务型会话以及设置消息的签收方式相关概念在后面会详细讲解之后再为本次会话创建管道即传输队列这里可以指定是创建队列Queue还是还是主题Topic最后创建消息对象发送到管道提交即完成本次会话的消息生产。 接下来看看消费者如何消费消息 public static void main(String[] args) {ConnectionFactory factory new ActiveMQConnectionFactory(tcp://192.168.0.106:61616);Connection connection null;try {connection factory.createConnection();connection.start();Session session connection.createSession(true, Session.AUTO_ACKNOWLEDGE);// 创建接收队列Destination destination session.createQueue(queue);// 创建消息消费者MessageConsumer consumer session.createConsumer(destination);// 接收消息TextMessage message (TextMessage) consumer.receive();System.out.println(message.getText());session.commit();session.close();} catch (JMSException e) {e.printStackTrace();} finally {try {connection.close();} catch (JMSException e) {e.printStackTrace();}} } 整个流程和生产者流程基本是一样的只不过消费者不再需要自己生产消息而是从消息队列中获取这里是通过 receive() 方法获取的该方法相当于是客户端主动从队列中“拉”消息并且在消息队列为空时会阻塞等待消息传入。 另外还有一种队列“推”送的方式通过监听器实现 public static void main(String[] args) {ConnectionFactory factory new ActiveMQConnectionFactory(tcp://192.168.0.106:61616);Connection connection null;try {connection factory.createConnection();connection.start();Session session connection.createSession(true, Session.AUTO_ACKNOWLEDGE);Destination destination session.createQueue(queue);MessageConsumer consumer session.createConsumer(destination);// 使用监听器监听队列MessageListener listener new MessageListener() {Overridepublic void onMessage(Message message) {try {System.out.println(((TextMessage) message).getText());} catch (JMSException e) {e.printStackTrace();}}};while (true) {consumer.setMessageListener(listener);session.commit();}} catch (JMSException e) {e.printStackTrace();} finally {try {connection.close();} catch (JMSException e) {e.printStackTrace();}} } 需要注意的是 listener 不会阻塞等待当消息到达时会主动调用 onMessage() 方法但它的生命周期和方法的生命周期是相同的需要像上面一样死循环监听同时 receive 和 listener 是互斥的即同时只能使用其中一种方式来获取消息。 3.3. Topic 模式Pub/Sub 相对于 P2P发布订阅模式就是可以有多个消费者监听同一个队列并可重复消费同一个消息整个代码实现流程和上面的是一样的只是将 Destination destination session.createQueue(“queue”); 改为 Destination destination session.createTopic(“topic”); 即可。 这里需要思考一个问题消费者能够订阅到哪个时间段的消息呢是所有的消息还是自消费者注册监听之后的呢很显然肯定是只能获取到注册监听之后的消息。但是若是消费者中途怠机再恢复怠机过程中产生的消息能否接收到呢AcitveMQ 是支持获取怠机过程中的消息的即持久订阅功能。 3.4. 持久订阅 什么是持久订阅举个例子相当于你在微博点击关注某个博主无论你是否在线博主发送的消息你都是可以获取到的持久订阅就类似这样在创建好连接后首先设置一个自身的身份标识clientId这个 id 是唯一的 connection.setClientID(lhzm); 然后通过下面 API 创建消费者即可创建持久订阅 MessageConsumer consumer session.createDurableSubscriber((Topic) destination, lhzm); 需要注意持久订阅只有 Pub/Sub 模式下才支持。 3.5. 消息传递的可靠性 在学习了基础的使用后我们应该考虑一个问题消息队列该如何保证消息传递的可靠性呢即如何保证生产的消息正确被消费者签收或者被生产者销毁这就牵涉到事务型会话和非事务型会话JMS Session 接口提供了 commit 和 rollback 方法。 事务提交意味着生产的所有消息被发送消费的所有消息被确认事务回滚意味着生产的所有消息被销毁消费的所有消息被恢复并重新提交除非它们已经过期。 事务型的会话总是牵涉到事务处理中commit 或 rollback 方法一旦被调用一个事务就结束了而另一个事务被开始关闭事务性会话将回滚其中的事务。 3.5.1. 事务型会话与非事务型会话 JMS 在创建 session 会话时通过第一个参数指定是否为事务型会话 Session session connection.createSession(true, Session.AUTO_ACKNOWLEDGE); 当为事务型会话时调用 commit 方法前消息并不会真正的投递到消息中间件中去而在调用commit 后消息会自动确认需要保证发送端和接收端都是事务型会话。 当为非事务型会话时相当于生产者逐个投递到消息中间件但是消息的确认取决于消费者如何设置 ACK_MODE即创建会话时的第二个参数该参数有4个选项 SESSION_TRANSACTED当为事务型会话时的默认选项若不是事务型会话设置该参数会抛出异常。AUTO_ACKNOWLEDGE当消费者成功的从 receive() 方法返回的时候或者从MessageListenner.onMessage() 方法成功返回的时候会话自动确认客户收到消息。CLIENT_ACKNOWLEDGE消费者通过调用 Message 的 acknowledge() 方法确认消息。需要注意该模式下何时调用 acknowledge() 方法那么在调用该方法之前收到的消息都会一起被确认而在此之后收到的消息不会被确认。比如发送10条消息消费者在收到第5条消息时调用 acknowledge() 方法那么前5条都会被确认。DUPS_OK_ACKNOWLEDGE消息延迟批量确认消息生产者在消费者没有确认消息时会重新发送消息。该模式可优化消费者确认消息的性能但可能会导致消费者收到重复消息。 需要注意第一个是和事务绑定后面三个都是针对消费端的即消息中间件需要接收到消费者的ack 才会认为消息被正确处理。 3.5.2. 持久化与非持久化消息的存储策略 消息队列为保证高效消息首先肯定是存储在内存中的那么一旦消息队列怠机或者消息过多超出内存消息就会面临丢失的风险所以需要有相关的手段来保证。 正常情况下非持久化消息是存储在内存中的能够存储的最大消息数据在 /conf/activemq.xml 文件中的 systemUsage 节点可配置 systemUsagesystemUsagememoryUsagememoryUsage percentOfJvmHeap70 //memoryUsagestoreUsagestoreUsage limit100 gb//storeUsagetempUsagetempUsage limit50 gb//tempUsage/systemUsage /systemUsage memoryUsage 是设置整个 ActiveMQ 节点的“可用内存限制”。这个值不能超过 ActiveMQ 本身设置的最大内存大小。其中的 percentOfJvmHeap 属性表示百分比。 storeUsage 是设置整个 ActiveMQ 节点用于存储“持久化消息”的“可用磁盘空间”。 tempUsage 是设置临时文件大小。一旦 ActiveMQ 服务节点存储的消息达到了 memoryUsage 的限制非持久化消息就会被转储到 temp store 区域虽然我们说过非持久化消息不进行持久化存储但是 ActiveMQ 为了防止数据洪峰出现时非持久化消息大量堆积致使内存耗尽的情况出现还是会将非持久化消息写入到磁盘的临时区域——temp store。 从上文我们可以了解到 ActiveMQ的 存储策略但是还有个问题持久化消息是通过什么介质存储的呢主要有以下 5 种 1. KahaDB默认的存储方式。在 data/kahadb 这个目录下会生成四个文件 db-*.log存储消息内容。新的数据以 APPEND 的方式追加到日志文件末尾。属于顺序写入因此消息存储是比较快的。默认是32M达到阀值会自动递增。db.data它是消息的索引文件本质上是 B-TreeB树使用 B-Tree 作为索引指向 db-*.log 里面存储的消息。db.redo用来进行消息恢复。lock 文件锁表示当前获得 kahadb 读写权限的 broker。 2. JDBC存储需要配置 JDBC 连接以及引入相应的 jar。会在数据库创建三张表 ACTIVEMQ_MSGS消息表Queue 和 Topic 都存在这个表中ACTIVEMQ_ACKS存储持久订阅的信息和最后一个持久订阅接收的消息 ID。ACTIVEMQ_LOCKS锁表用来确保某一时刻只能有一个 ActiveMQ broker 实例来访问数据库。 3. Memory存储即内存。 4. LevelDB存储性能优于 KahaDB但官方不推荐使用。 5. JDBC Message store with ActiveMQ Journal这种方式克服了 JDBC Store 的不足JDBC每次消息过来都需要去写库和读库。ActiveMQ Journal使用高速缓存写入技术大大提高了性能。 详细配置方式参照官方文档。 3.6. 消息发送策略 ActiveMQ 支持同步、异步两种发送模式将消息发送到消息中间件上。 同步发送过程中发送者发送一条消息会阻塞直到消息中间件反馈一个确认消息表示消息已经被消息中间件处理。这个机制提供了消息的安全性保障但是由于是阻塞的操作会影响到客户端消息发送的性能。 异步发送的过程中发送者不需要等待 broker 提供反馈所以性能相对较高。但是可能会出现消息丢失的情况。所以使用异步发送的前提是在某些情况下允许出现数据丢失的情况。 默认情况下非持久化消息是异步发送的持久化消息并且是在非事务模式下是同步发送的。但是在开启事务的情况下消息都是异步发送。由于异步发送的效率会比同步发送性能更高所以在发送持久化消息的时候尽量去开启事务会话。除了持久化消息和非持久化消息的同步和异步特性以外我们还可以通过以下几种方式来设置异步发送 ConnectionFactory connectionFactory new ActiveMQConnectionFactory(tcp://192.168.0.106:61616?jms.useAsyncSendtrue); ((ActiveMQConnectionFactory) connectionFactory).setUseAsyncSend(true); ((ActiveMQConnection) connection).setUseAsyncSend(true); 3.7. Failover 参数配置 默认的情况下这种协议用于随机的去选择一个链接去连接如果连接失败了那么会连接到其他的 Broker 上。默认配置定义了延迟重新连接意味着传输将会在 10s 后自动去重新连接可用的broker。当然所以有的重新连接参数都可以根据应用的需要而配置的。 选项名默认值说明backupfalse提前初始化一个未使用的链接以便进行快速的失败转移默认falseinitialReconnectDelay10在第一次尝试重新连接之前等待的时间长度毫秒默认10maxCacheSize131072当trackMessage启动时缓存的最大子接默认为127*1024bytesmaxReconnectAttempts-1 | 0默认1|0自5.6版本开始-1为默认值代表不限重试次数0标识从不重试只尝试连接一次并不重连5.6以前的版本0为默认值代表不重试如果设置大于0的数则代表最大重试次数。maxReconnectDelay30000最长重连时间间隔毫秒默认30000nested.*null来自ActiveMQ 5.9将应用于列表中每个URI的通用URI选项。randomizetrue使用随机连接以达到负载均衡的目的默认truereconnectDelayExponent2.0在指数后退尝试过程中使用的指数。reconnectSupportedtrue确定客户端是否应通过重新连接来响应 broker ConnectionControl 事件请参阅rebalanceClusterClients。startupMaxReconnectAttempts-1初始化时的最大重试次数一旦连接上将使用maxReconnectAttempts的配置默认0timeout-1从ActiveMQ 5.3开始在不中断重新连接过程的情况下设置发送操作的超时以毫秒为单位。trackMessagesfalse设置是否缓存故障发生时尚未传送完成的消息当broker一旦重新连接成功便将这些缓存中的消息刷新到新连接的代理中使得消息可以在broker切换前后顺利传送。默认falseupdateURIsSupportedtrue设定是否可以动态修改 broker uri自5.4版本开始默认trueupdateURIsURLnull从ActiveMQ 5.4指向文本文件的URL或本地文件的路径该文本文件包含一个逗号分隔的URI列表用于在失败时重新连接。useExponentialBackOfftrue重连时间间隔是否以指数形式增长默认truewarnAfterReconnectAttempts10从ActiveMQ 5.10:值0指定在记录警告之前重新连接尝试的次数。记录的警告表示当前没有连接但正在尝试重新连接。值0将禁用有关重新连接尝试的警告的日志记录。 四. 原理解析 ActiveMQ 的上手非常简单但仅仅只是会用肯定不行只有了解其原理才能对特定的场景做出优化和设计而要了解其原理只有通过分析其源码才能完全了解。接下来针对生产消息、消费消息和消息重发机制的流程做一个概括性总结。 4.1. 生产消息原理 生产消息流程 上面就是整个发消息的流程图当生产者调用 send 发送消息时首先会判断producerWindowSize 是否还有空间若没有了就阻塞等待空间反之则继续判断是否是异步发送消息如果是同步则直接通过底层传输协议传输消息并阻塞等待 response 结果如果是异步发送同样通过底层传输协议传输消息但不再需要阻塞等待 response同时会去增加 producerWindowSize 的值。 什么是 producerWindowSize这个配置主要用来约束异步发送时 producer 端允许积压未 ack的消息大小。当发送消息时首先会判断 producerWindowSize 是否还有剩余空间如果没有就阻塞等待空间释放即等待 broker可以就当作是消息队列中间件确认消息如果有空间就放入到该空间下等待 broker 处理。可以通过以下两种方式配置 在连接 url 中设置对所有 producer 都有效tcp://localhost:61616?jms.producerWindowSize1048576在 destination 名称中设置仅对使用该 destination 的 producer 有效并且优先级更高test-queue?producer.windowSize1048576 4.2. 消费消息原理 消费消息流程 消费者在通过 receive() 消费消息时并不是直接去 broker 上获取的消息而是从本地的unconsumerMessage 队列中获取而该队列则是每次批量从 broker 上拉取消息每次拉取的数量就是由 prefetchSize 控制的。当队列中没有消息时就会阻塞等待获取消息反之则依次从unconsumerMessage 队列中取出消息消费并将应答放到 delivered 队列返回给 broker消费消息和 ack 是异步的。下面我们来看看消息的确认过程。 4.3. 消息确认及消息重发 看到上面这张图可能会比较懵没关系我们首先来了解一下 ACK_MODE 和 ACK_TYPEACK_MODE 在上文已经讲过了但仅仅是消费端确认了还不够还需要让 broker 知道消息是否正常消费因此在确认消息后消费者还会根据处理结果返回不同的 ACK_TYPE 给 brokerACK_TYPE 一共有以下 6 种 DELIVERED_ACK_TYPE 0 消息已接收但尚未处理结束。POSION_ACK_TYPE 1 消息错误通常表示“抛弃”此消息比如消息重发多次后都无法正确处理时消息将会被删除或者加入 DLQ死信队列。STANDARD_ACK_TYPE 2 “标准类型通常表示为消息“处理成功”broker 端可以删除消息了。REDELIVERED_ACK_TYPE 3 消息需“重发”比如 consumer 处理消息时抛出了异常broker 稍后会重新发送此消息。INDIVIDUAL_ACK_TYPE 4 表示无论在任何 ACK_MODE 下只确认“单条消息”。UNMATCHED_ACK_TYPE 5 在 Topic 中如果一条消息在转发给“订阅者”时发现此消息不符合 Selector 过滤条件那么此消息将不会转发给订阅者消息将会被存储引擎删除相当于在 Broker 上确认了消息。EXPIRED_ACK_TYPE 6 消息已过期。 清楚了 ACK_TYPE 所对应的意思后再看这张图就很明了了。首先从 unconsumerMessage 队列中取出消息并处理若消费消息出现异常失败消费者就会返回 REDELIVERED_ACK_TYPE 给brokerbroker 就会重发该条消息当超过次数限制消费者就会返回 POSION_ACK_TYPE 告诉broker 该条消息是有毒的broker 根据配置将该条消息抛弃或是加入死信队列中该队列可以被重新消费若消费消息成功未出现异常就会将 ack message 添加到 delivered 队列中消费该队列的消息时会进行一系列判断并根据结果返回不同的 ACK_TYPE。 刚刚我们提到消息消费失败会导致消息重发那究竟在哪些情况下会被重发呢主要有以下几种情况 在事务型会话中若是没有调用 session.commit() 提交确认消息或者调用 session.rollback() 方法。在非事务性会话中ACK 模式为 CLIENT_ACKNOWLEDGE 的情况下没有调用 acknowledge() 或者调用了 recover() 方法。处理消息时发生异常。 这就是整个消息的确认和重发原理。  五. 基本优化 在上文我们提到过 prefetchSize 配置该配置表示消费者每次从队列中获取消息的条数该配置为 0 时表示消费者通过 pull 方式从 broker 获取消息另外不同类型的队列具有不同的默认值 持久化队列和非持久化队列的默认值为 1000持久化 topic 默认值为 100非持久化 topic 的默认值为 Short.MAX_VALUE-1。 但是仅仅只有批量获取肯定是不够的因为从上文我们知道消息还有一个确认过程如果还是单个单个的确认那这个批量获取就没有什么意义了除了第一次是批量获取消息后面都是单个单个的获取消息所以 ActiveMQ 还提供了 optimizeAcknowledge 配置该参数为 true 时消费者会延迟确认默认是 ack 了 0.65*prefetchSize 个消息后才确认。该配置可以直接在连接url中配置其中 optimizeAcknowledgeTimeOut 是表示超过该时间也会自动确认  ConnectionFactory connectionFactory new ActiveMQConnectionFactory( tcp://192.168.0.106:61616?jms.optimizeAcknowledgetruejms.optimizeAcknowledgeTimeOut10000); 因此这两者协同配合才能起到优化的作用。另外需要注意的是如果消费端的消费速度比较高通过这两者组合能大大提升消费者的性能。如果消费者的消费性能本身就比较慢设置比较大的 prefetchSize 反而不能有效的达到提升消费性能的目的因为过大的 prefetchSize 会导致某一消费端积压消息而其它的消费端却“无所事事”。同时该方案需要消费端能够容忍重复消息因为当消息还未确认时消费者就怠机了那么 broker 就会将该消息重发给其它消费者导致消息重复。 六. 总结 通过以上学习我们能看出 ActiveMQ 是非常简单易上手的但它有以下缺点 持久化消息存储需要建立索引因此吞吐量低不适合 TPS 要求高的业务。不支持消息分片功能只能自己实现。
http://www.zqtcl.cn/news/913432/

相关文章:

  • 建设企业网银如何对账seo优化推广工程师
  • 广州制作外贸网站小说网站制作公司
  • 东莞南城网站建设价格注册深圳公司有什么好处
  • 做网站图片大小建个人网站要多少钱
  • 北京免费建网站seo网站关键词
  • 南宁网站制作公司dede网站建站教程
  • 辽宁省建设工程招标协会网站自建网站主题及策划
  • 石材做网站google建网站
  • 装配式建筑信息平台无忧seo博客
  • 做淘客网站用备案网络推广预算方案
  • 网站建设需不需要招标好网站欣赏
  • 怎样创建网站的代码此网站域名即将过期
  • 网页转向网站jquery图片效果网站
  • 山东定制网页建站wordpress是是什么技术
  • 无锡免费网站制作手游网页版
  • 东莞 网站建设 定制水寻找常州微信网站建设
  • 在门户网站做推广网站开发需要20万
  • 网站做电商销售需要注册吗上海的公司地址
  • 给网站做选题计算机网络技术电商网站建设与运营方向
  • 网站如何做熊掌号并绑定wordpress pdf
  • wordpress页面构建器中文文山seo公司
  • 凡科免费做网站蜂箱尺寸与制作图片
  • 完全不收费的聊天软件班级优化大师下载安装app
  • 合肥网站改版360免费建站永久免费
  • 商业网站建设案例课程 下载工信部企业网站认证
  • 泉州网站设计哪家公司好沈阳seo代理计费
  • 做景观素材有哪几个网站国内建网站费用
  • 驻马店重点项目建设网站wordpress常规选项
  • 网站开发 英文网站策划建设阶段的推广
  • 建立网站一般多少钱wordpress评论跳过验证