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

rabbitmq五种模式的实现——springboot

rabbitmq五种模式的实现——springboot

基础知识和javase的实现形式可以看我之前的博客

代码地址:https://github.com/9lucifer/rabbitmq4j-learning

一、进行集成

(一)Spring Boot 集成 RabbitMQ 概述

Spring Boot 提供了对 RabbitMQ 的自动配置支持,通过 RabbitTemplate@RabbitListener 可以方便地实现消息的生产和消费。以下是基于 Spring Boot 的 RabbitMQ 集成示例。


(二)生产者代码解析

生产者负责创建消息并将其发送到指定的队列中。

1. 配置文件(application.yml)
spring:rabbitmq:host: 自己服务器的ip       # RabbitMQ 服务器地址port: 5672               # RabbitMQ 端口号username: admin          # RabbitMQ 用户名password: admin          # RabbitMQ 密码virtual-host: /          # 虚拟主机(默认是 /)
server:port: 8081                 # 应用端口
2. 生产者代码(Controller)
package top.miqiu.controller;import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;@RestController
public class SendController {@Autowiredprivate RabbitTemplate rabbitTemplate;@GetMapping("/sendMsg")public String sendMsg(@RequestParam String msg) {// 发送消息到队列 boot_queuerabbitTemplate.convertAndSend("", "boot_queue", msg);return "发送成功: " + msg;}
}
关键
  1. RabbitTemplate:Spring 提供的 RabbitMQ 操作模板,用于发送消息。
  2. convertAndSend:发送消息到指定队列。
  3. @GetMapping:定义一个 GET 请求接口,路径为 /sendMsg
效果

image-20250216093813082


(三)消费者代码解析

消费者负责从队列中接收并处理消息。

消费者代码(Listener)
package top.miqiu.controller;import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;@Component
public class Receive {@RabbitListener(queuesToDeclare = @Queue("boot_queue"))public void consumer(String msg) {System.out.println("消息内容为:" + msg);}
}
关键
  1. @RabbitListener:监听指定队列,当队列中有消息时,自动调用 consumer 方法。
  2. queuesToDeclare:如果队列不存在,会自动创建队列。
效果

image-20250216093839842

二、工作模式

(一)生产者

  1. 生产者通过 RabbitTemplate 将消息发送到 RabbitMQ 的队列中。

  2. 关键代码解析

    java复制

    rabbitTemplate.convertAndSend("", "boot_work", msg + i);
    
    • rabbitTemplate:RabbitMQ 的核心操作类,用于发送消息。
    • convertAndSend 方法
      • 第一个参数是交换机名称(这里为空字符串,表示默认交换机)。
      • 第二个参数是队列名称(boot_work)。
      • 第三个参数是消息内容(msg + i)。
    • 循环发送:代码中通过循环发送了 20 条消息,每条消息内容为 msg + i
  3. 运行逻辑
    生产者调用 /sendMsg 接口时,会将消息发送到队列 boot_work 中,消息内容为循环生成的字符串。


(二)消费者

  1. 功能描述
    消费者从队列中接收消息并处理,处理完成后发送确认信号。

  2. 关键代码解析

    @RabbitListener(queuesToDeclare = @Queue("boot_work"))
    
    • @RabbitListener:注解用于监听指定队列的消息。
    • queuesToDeclare:声明队列名称(boot_work)。
    • @Queue:声明队列的详细信息。
    public void consumer(String msg,@Header(AmqpHeaders.DELIVERY_TAG) long deliveryTag,Channel channel
    ) throws IOException, InterruptedException {Thread.sleep(1000); // 模拟消息处理时间channel.basicAck(deliveryTag, true); // 确认消息已处理System.out.println("消费者1 消息内容为:" + msg);
    }
    
    • msg:接收到的消息内容。
    • deliveryTag:消息的唯一标识,用于确认消息是否成功处理。
    • Channel:RabbitMQ 的通道,用于执行消息确认操作。
    • basicAck:确认消息已处理,避免消息重复发送。
      • 第一个参数是 deliveryTag
      • 第二个参数是 multiple,表示是否批量确认。
  3. 运行逻辑
    消费者监听队列 boot_work,接收到消息后模拟处理时间(Thread.sleep(1000)),然后通过 channel.basicAck 发送确认信号,表示消息已处理完成。

(三)效果

image-20250216102608684

可以看到休眠的时长不同,消费的速度不同,侧面证明该模式适用于任务分配场景,多个消费者可以并行处理任务,提高效率。

三、Pub/Sub 模式

(一)Pub/Sub 模式概述

Pub/Sub(发布/订阅)模式是一种消息传递模式,生产者将消息发送到一个交换机(Exchange),而不是直接发送到队列。消费者通过绑定交换机来接收消息。这种模式允许多个消费者订阅同一个消息源,实现消息的广播。

(二)生产者

  1. 功能描述
    生产者通过 RabbitTemplate 将消息发送到一个名为 boot-pubsub 的交换机。

  2. 关键代码解析

    rabbitTemplate.convertAndSend("boot-pubsub", "", msg);
    
    • convertAndSend 方法
      • 第一个参数是交换机名称(boot-pubsub)。
      • 第二个参数是路由键(这里为空字符串,表示不指定路由键)。
      • 第三个参数是消息内容(msg)。
    • 交换机类型boot-pubsub 是一个 fanout 类型的交换机,它会将消息广播到所有绑定的队列。
  3. 运行逻辑
    生产者调用 /sendPubsub 接口时,将消息发送到 boot-pubsub 交换机,交换机会将消息广播到所有绑定的队列。

  4. 运行结果

    image-20250216104227902


(三)消费者

  1. 功能描述
    消费者通过绑定到 boot-pubsub 交换机接收消息,并处理接收到的消息。

  2. 关键代码解析

    @RabbitListener(bindings =@QueueBinding(value = @Queue,exchange = @Exchange(value = "boot-pubsub", type = "fanout")))
    public void consumer(String msg) {System.out.println("consumer 4 消息内容为:" + msg);
    }
    
    • @RabbitListener:注解用于监听消息。
    • @QueueBinding:声明队列与交换机的绑定关系。
      • value = @Queue:声明一个匿名队列。
      • exchange = @Exchange:声明交换机的名称(boot-pubsub)和类型(fanout)。
    • consumer 方法:处理接收到的消息,并打印消息内容。
  3. 运行逻辑
    消费者绑定到 boot-pubsub 交换机,接收所有广播的消息,并打印消息内容。

  4. 运行效果

    image-20250216104255415


(四)Pub/Sub 模式特点

  1. 广播机制
    生产者发送的消息会被广播到所有绑定到交换机的队列,多个消费者可以同时接收相同的消息。
  2. 解耦合
    生产者和消费者之间通过交换机解耦,生产者无需知道消费者的存在,消费者也无需知道生产者的存在。
  3. 动态绑定
    可以动态添加或移除消费者,而无需修改生产者的代码。


四、Routing 模式

(一)Routing 模式概述

Routing 模式是一种基于路由键(Routing Key)的消息路由模式。生产者将消息发送到 direct 类型的交换机,并指定一个路由键。消费者通过绑定到交换机并指定绑定键(Binding Key)来接收消息。只有路由键与绑定键完全匹配时,消息才会被路由到对应的队列。


(二)生产者

  1. 功能描述
    生产者通过 RabbitTemplate 将消息发送到 boot-routing 交换机,并指定路由键(key)。

  2. 关键代码解析

    rabbitTemplate.convertAndSend("boot-routing", key, msg);
    
    • boot-routing:交换机名称,类型为 direct
    • key:路由键,由方法参数传入,用于指定消息的路由规则。
    • msg:消息内容,由方法参数传入。
  3. 运行逻辑
    生产者调用 /sendRouting 接口时,将消息发送到 boot-routing 交换机,并通过路由键决定消息的去向。

image-20250216113239428


(三)消费者

  1. 功能描述
    消费者通过绑定到 boot-routing 交换机接收消息,并处理接收到的消息。

  2. 关键代码解析

    @RabbitListener(bindings =@QueueBinding(value = @Queue,exchange = @Exchange(value = "boot-routing", type = "direct"),key = {"trace"}))
    public void consumer(String msg) {System.out.println("consumer 6 消息内容为:" + msg);
    }
    
    • @RabbitListener:注解用于监听消息。
    • @QueueBinding:声明队列与交换机的绑定关系。
      • value = @Queue:声明一个匿名队列。
      • exchange = @Exchange:声明交换机的名称(boot-routing)和类型(direct)。
      • key = {"trace"}:绑定键,表示该队列只接收路由键为 trace 的消息。
    • consumer 方法:处理接收到的消息,并打印消息内容。
  3. 运行逻辑
    消费者绑定到 boot-routing 交换机,并通过绑定键 trace 接收匹配的消息。

image-20250216113302874


(四)Routing 模式特点

  1. 精确匹配
    direct 类型的交换机要求路由键与绑定键完全匹配,消息才会被路由到对应的队列。

  2. 多队列绑定
    一个交换机可以绑定多个队列,每个队列可以指定不同的绑定键。

  3. 解耦合
    生产者和消费者之间通过交换机解耦,生产者无需知道消费者的存在,消费者也无需知道生产者的存在。

五、Topic 模式

(一)Topic 模式概述

Topic 模式是一种灵活的发布/订阅消息模式,适用于需要根据动态路由规则分发消息的场景。生产者将消息发送到一个 topic 类型的交换机,并指定一个路由键(Routing Key)。消费者通过绑定交换机并指定匹配规则(Binding Key)来接收消息。topic 类型的交换机支持模糊匹配,允许更灵活的消息路由。

(二)生产者

  1. 功能描述
    生产者通过 RabbitTemplate 将消息发送到 boot-topic 交换机,并指定路由键(key)。

  2. 关键代码解析

    rabbitTemplate.convertAndSend("boot-topic", key, msg);
    
    • boot-topic:交换机名称,类型为 topic
    • key:路由键,由方法参数传入,用于指定消息的路由规则。例如,user.loginuser.register
    • msg:消息内容,由方法参数传入。
  3. 运行逻辑
    生产者调用 /sendTopic 接口时,将消息发送到 boot-topic 交换机,并通过路由键决定消息的去向。交换机会根据绑定规则将消息路由到匹配的队列。

image-20250216123803069


(三)消费者

  1. 功能描述
    消费者通过绑定到 boot-topic 交换机接收消息,并处理接收到的消息。

  2. 关键代码解析

    @RabbitListener(bindings =@QueueBinding(value = @Queue,exchange = @Exchange(value = "boot-topic", type = "topic"),key = {"user.*"}))
    public void consumer(String msg) {System.out.println("consumer 8 user.* 消息内容为:" + msg);
    }
    
    • @RabbitListener:注解用于监听消息。
    • @QueueBinding:声明队列与交换机的绑定关系。
      • value = @Queue:声明一个匿名队列。
      • exchange = @Exchange:声明交换机的名称(boot-topic)和类型(topic)。
      • key = {"user.\*"}:绑定键,表示该队列只接收路由键以 user. 开头的消息(例如 user.loginuser.register)。
    • consumer 方法:处理接收到的消息,并打印消息内容。
  3. 运行逻辑
    消费者绑定到 boot-topic 交换机,并通过绑定键 user.* 接收匹配的消息。例如,生产者发送路由键为 user.login 的消息时,该消费者会接收并处理该消息。

    image-20250216123818814


(四)Topic 模式特点

  1. 灵活的路由规则
    • topic 类型的交换机支持模糊匹配:
      • *(星号):匹配一个单词。
      • #(井号):匹配零个或多个单词。
    • 例如,路由键为 user.login 的消息可以被绑定键为 user.*user.login 的队列接收。
  2. 动态绑定
    消费者可以根据需要动态绑定不同的队列,而无需修改生产者的代码。
  3. 解耦合
    生产者和消费者之间通过交换机解耦,生产者无需知道消费者的存在,消费者也无需知道生产者的存在。

(五)注意事项

  1. 交换机类型
    确保交换机类型为 topic,因为 topic 类型的交换机支持模糊匹配。
  2. 绑定键的正确性
    消费者需要正确设置绑定键(key),否则无法接收到匹配的消息。
  3. 路由键的格式
    路由键应使用点分隔符(.),例如 user.logintrace.error,以符合 topic 交换机的匹配规则。
  4. 队列声明
    如果使用匿名队列(@Queue),队列会在消费者启动时自动创建,但在 RabbitMQ 管理界面中可能看不到队列名称。如果需要持久化队列,可以显式声明队列名称。
  5. 消息丢失问题
    如果没有消费者绑定到匹配的路由键,消息可能会丢失。可以通过设置交换机的 DLX(Dead Letter Exchange)来处理未消费的消息。

相关文章:

rabbitmq五种模式的实现——springboot

rabbitmq五种模式的实现——springboot 基础知识和javase的实现形式可以看我之前的博客 代码地址:https://github.com/9lucifer/rabbitmq4j-learning 一、进行集成 (一)Spring Boot 集成 RabbitMQ 概述 Spring Boot 提供了对 RabbitMQ 的自…...

每日学习Java之一万个为什么

9.Class <?> class1 Myclass.class 为什么要有通配符&#xff1f;传给谁用的&#xff1f; 首先&#xff0c;这里的class特指某个对象在JVM中的元数据集合。 有普通、接口、数组、基本类型、 void 类型、局部类、匿名类、枚举、注解 1.类型安全&#xff1a;通配符允许…...

寒假学习总结

整个寒假都走在数据结构与算法的路上&#xff0c;深入学习了其中多个板块&#xff0c;刷了一些与之对应的题目&#xff0c;下面来一期总结&#xff08;c&#xff09; &#xff08;emmm&#xff0c;主播在寒假试着去学习了几大语言的语法基础&#xff08;丢丢&#xff09; 如Ja…...

Java Web开发实战与项目——用户认证与授权模块开发

Web应用中&#xff0c;用户认证与授权是至关重要的功能&#xff0c;确保只有合法用户才能访问受保护的资源。Spring Security作为一个强大的安全框架&#xff0c;支持多种认证与授权方式。在本章节中&#xff0c;我们将深入探讨三种常见的用户认证与授权方案&#xff1a;基于To…...

力扣每日一题【算法学习day.129】

前言 ###我做这类文章一个重要的目的还是记录自己的学习过程&#xff0c;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&#xff01;&#xff01;&#xff01; 习题 1.数组列表中的最大距离 题目链接…...

uni-app发起网络请求的三种方式

uni.request(OBJECT) 发起网络请求 具体参数可查看官方文档uni-app data:请求的参数; header&#xff1a;设置请求的 header&#xff0c;header 中不能设置 Referer&#xff1b; method&#xff1a;请求方法&#xff1b; timeout&#xff1a;超时时间&#xff0c;单位 ms&a…...

字节火山云DeepSeek接入教程,支持联网,速度超快。

大家好&#xff0c;我是苍何。 在使用 DeepSeek 官网&#xff0c;实在是卡的我差点学猪叫&#xff0c;于是我一直在寻找替代方案。 要求就 2&#xff1a;满血&#xff0c;速度快。&#xff08;当然能联网更好&#xff09;。 我也一度使用了如硅基流动 API&#xff0c;发现也开…...

C语言指针学习笔记

1. 指针的定义 指针&#xff08;Pointer&#xff09;是存储变量地址的变量。在C语言中&#xff0c;指针是一种非常重要的数据类型&#xff0c;通过指针可以直接访问和操作内存。 2. 指针的声明与初始化 2.1 指针声明 指针变量的声明格式为&#xff1a;数据类型 *指针变量名…...

FreeRTOS-rust 编译分析

目录介绍 FreeRTOS-rust ├── .cargo # 对 cargo 本身的配置 │ └── config.toml ├── Cargo.toml # 对当前工作空间的配置 ├── freertos-cargo-build # 负责对 freertos 源码进行编译 │ ├── Cargo.toml # 对当前 package 进行配置 │ └…...

【解决方法】vite-plugin-svg-icons使用中出现问题[vite] Cannot find package ‘fast-glob‘

问题长这样&#xff1a; 参考文章&#xff1a;https://medium.com/wumeng9028/vite-plugin-svg-icons-error-cannot-find-package-fast-glob-8cb03d19c0ac 解决方法&#xff1a;pnpm add fast-glob -D package.json {"vite-plugin-svg-icons": "2.0.1"…...

[Qt] 使用QUndoStack运行到cmd->isObsolete()崩溃

redo/undo中又push了 崩溃情况崩溃原因解决方法 崩溃情况 在正常调用QUndoStack的redo/undo时&#xff0c;崩溃在了这里 unknown:0 QWidget: Cannot create a QWidget without QApplication. 崩溃原因 在正常调用QUndoStack的redo/undo时&#xff0c;因为自身的逻辑处理&a…...

大白话实战Sentinel

Sentinel是SpringCloudAlibaba提供的用来做服务保护的框架,而服务保护的常见手段就是限流和熔断降级。在大型分布式系统里面,由于微服务众多,所以服务之间的稳定性需要做特别关注,Sentinel的核心包就提供了从多个维度去保护服务稳定的策略,而且这些保护策略都可以连接上Se…...

DL/CV领域常见指标术语(FLOPS/mIoU/混淆矩阵/F1-measure)------一篇入门

1. FLOPS、FLOPs和GFLOPs FLOPS: floating-point operations per second&#xff0c;每秒浮点运算次数&#xff0c;用来衡量硬件性能。 FLOPs&#xff1a;floating point of operations&#xff0c;是浮点运算次数&#xff0c;用来衡量算法、模型的复杂度。 GFLOPS&#xff…...

SprutCAMX16数控软件介绍

SprutCAM X 16 是一款功能强大的CAM&#xff08;计算机辅助制造&#xff09;软件&#xff0c;专为数控机床编程和制造过程优化设计。它广泛应用于机械加工、模具制造、3D打印等领域&#xff0c;支持多轴加工、车铣复合、机器人加工等多种加工方式。以下是SprutCAM X 16的主要特…...

Miniconda + VSCode 的Python环境搭建

目录&#xff1a; 安装 VScode 安装 miniconda 在VScode 使用conda虚拟环境 运行Python程序 1.安装 vscode 编辑器 官网链接&#xff1a;Visual Studio Code - Code Editing. Redefined 下载得到&#xff1a;&#xff0c;双击安装。 安装成功…...

TRELLIS 部署笔记

目录 依赖项安装 kaolin安装&#xff1a; 安装和运行报错解决 u2net.onnx 下载 解决方法&#xff0c;就是自行下载&#xff0c;然后拷贝到目录/root/.u2net bash测试u2net&#xff1a; 报错GaussianRasterizationSettings.__new__() got an unexpected keyword argument…...

深入解析Qt事件循环

在Qt开发中&#xff0c;QApplication::exec()这行代码是每个开发者都熟悉的“魔法咒语”。为什么GUI程序必须调用它才能响应操作&#xff1f;为何耗时操作会导致界面冻结&#xff1f;本文将以事件循环为核心&#xff0c;揭示Qt高效运转的底层逻辑&#xff0c;探讨其设计哲学与最…...

Visual Studio Code 集成 Baidu Comate

文章目录 安装Baidu Comate插件 安装Baidu Comate插件 从左主侧栏中 点击 【扩展】这个图标&#xff0c;然后在上方输入栏中输入 baidu comate —>选中列出的Bai Comate —>点击 【安装】按钮&#xff0c;等待安装完毕…...

「正版软件」PDF Reader - 专业 PDF 编辑阅读工具软件

PDF Reader 轻松查看、编辑、批注、转换、数字签名和管理 PDF 文件&#xff0c;以提高工作效率并充分利用 PDF 文档。 像专业人士一样编辑 PDF 编辑 PDF 文本 轻松添加、删除或修改 PDF 文档中的原始文本以更正错误。自定义文本属性&#xff0c;如颜色、字体大小、样式和粗细。…...

Kafka消息服务之Java工具类

注&#xff1a;此内容是本人在另一个技术平台发布的历史文章&#xff0c;转载发布到CSDN&#xff1b; Apache Kafka是一个开源分布式事件流平台&#xff0c;也是当前系统开发中流行的高性能消息队列服务&#xff0c;数千家公司使用它来实现高性能数据管道、流分析、数据集成和关…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

TDengine 快速体验(Docker 镜像方式)

简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能&#xff0c;本节首先介绍如何通过 Docker 快速体验 TDengine&#xff0c;然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker&#xff0c;请使用 安装包的方式快…...

《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》

引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

高防服务器能够抵御哪些网络攻击呢?

高防服务器作为一种有着高度防御能力的服务器&#xff0c;可以帮助网站应对分布式拒绝服务攻击&#xff0c;有效识别和清理一些恶意的网络流量&#xff0c;为用户提供安全且稳定的网络环境&#xff0c;那么&#xff0c;高防服务器一般都可以抵御哪些网络攻击呢&#xff1f;下面…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

Java多线程实现之Thread类深度解析

Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖

在Vuzix M400 AR智能眼镜的助力下&#xff0c;卢森堡罗伯特舒曼医院&#xff08;the Robert Schuman Hospitals, HRS&#xff09;凭借在无菌制剂生产流程中引入增强现实技术&#xff08;AR&#xff09;创新项目&#xff0c;荣获了2024年6月7日由卢森堡医院药剂师协会&#xff0…...