XA协议和Tcc

基于 XA 协议的两阶段提交 (2PC)。这是一种分布式事务协议,旨在保证在多个参与者(通常是不同的数据库或资源管理器)共同参与的事务中,所有参与者要么都提交事务,要么都回滚事务,从而维护数据的一致性。

你可以把 2PC 想象成一个需要多个部门共同签字才能生效的合同审批流程。每个部门都有同意或拒绝的权利,最终结果取决于所有部门的意见。

核心思想:协调者与参与者

在 2PC 中,有两个关键的角色:

  1. 协调者 (Coordinator): 负责整个事务的协调和管理。它向所有参与者发出指令,并收集它们的响应,最终决定事务是提交还是回滚。
  2. 参与者 (Participants): 参与到分布式事务中的各个资源管理器(例如,数据库)。它们接收协调者的指令,执行本地事务,并告知协调者自己的状态。

两阶段提交的过程

2PC 的过程分为两个关键阶段:

第一阶段(准备阶段 - Prepare Phase)

  1. 协调者询问 (Prepare Request): 协调者向所有参与者发送一个“准备请求”,询问它们是否准备好提交事务。这个请求包含了要执行的事务操作信息。

  2. 参与者执行本地事务 (Local Transaction Execution): 收到准备请求后,每个参与者执行本地事务操作,并在本地保存相关的 undo/redo 日志等信息,以便在后续需要回滚或提交时使用。注意:这里参与者只是执行操作,但并不真正提交。

  3. 参与者响应 (Vote): 每个参与者根据本地事务的执行情况,向协调者发送一个“投票”:

    • “同意 (Vote-Commit)”: 表示本地事务执行成功,参与者已经准备好提交。
    • “拒绝 (Vote-Abort)”: 表示本地事务执行失败,参与者不能提交,希望回滚。

第二阶段(提交/回滚阶段 - Commit/Rollback Phase)

协调者在收集到所有参与者的投票后,会根据投票结果决定下一步的操作:

情况一:所有参与者都投了“同意”票

  1. 协调者发送提交请求 (Commit Request): 协调者向所有参与者发送“提交请求”。

  2. 参与者提交本地事务 (Local Transaction Commit): 收到提交请求后,每个参与者正式提交之前在本地执行的事务。

  3. 参与者发送确认 (Acknowledgement): 参与者完成提交后,向协调者发送“提交确认”。

  4. 协调者完成事务 (Transaction Completion): 协调者收到所有参与者的提交确认后,认为整个分布式事务成功完成。

情况二:任何一个或多个参与者投了“拒绝”票,或者协调者在规定时间内没有收到所有参与者的投票

  1. 协调者发送回滚请求 (Rollback Request): 协调者向所有投了“同意”票的参与者(如果存在)以及投了“拒绝”票的参与者发送“回滚请求”。

  2. 参与者回滚本地事务 (Local Transaction Rollback): 收到回滚请求后,每个参与者利用之前保存的 undo 日志撤销之前执行的本地事务操作。

  3. 参与者发送确认 (Acknowledgement): 参与者完成回滚后,向协调者发送“回滚确认”。

  4. 协调者完成事务 (Transaction Completion): 协调者收到所有参与者的回滚确认后,认为整个分布式事务已回滚。

一个简单的转账例子

假设我们有两个不同的银行数据库参与一个跨行转账事务:

  • 参与者 A: 存储用户 A 的账户信息(在 Bank A 的数据库中)。
  • 参与者 B: 存储用户 B 的账户信息(在 Bank B 的数据库中)。
  • 协调者: 一个专门的事务管理器。

事务: 用户 A 向用户 B 转账 100 元。

第一阶段(准备阶段)

  1. 协调者发送准备请求: “请参与者 A 准备从用户 A 账户扣除 100 元,参与者 B 准备向用户 B 账户增加 100 元。”

  2. 参与者 A 执行本地事务: Bank A 的数据库执行了扣除操作,但未提交,记录了 undo 日志(如果需要回滚,就加回 100 元)。参与者 A 投票“同意”。

  3. 参与者 B 执行本地事务: Bank B 的数据库执行了增加操作,但未提交,记录了 redo 日志(如果需要提交,就确认增加 100 元)。参与者 B 投票“同意”。

  4. 协调者收到所有“同意”票。

第二阶段(提交阶段)

  1. 协调者发送提交请求: “请参与者 A 和参与者 B 提交事务。”

  2. 参与者 A 提交本地事务: Bank A 的数据库正式提交了扣除 100 元的操作。参与者 A 发送“提交确认”。

  3. 参与者 B 提交本地事务: Bank B 的数据库正式提交了增加 100 元的操作。参与者 B 发送“提交确认”。

  4. 协调者收到所有“提交确认”,事务成功完成。

如果第一阶段有参与者投了“拒绝”票(例如,用户 A 账户余额不足):

第一阶段(准备阶段)

  1. 参与者 A 执行本地事务,发现余额不足,投票“拒绝”。
  2. 参与者 B 可能仍然投票“同意”(因为它不知道 A 的情况)。
  3. 协调者收到至少一个“拒绝”票。

第二阶段(回滚阶段)

  1. 协调者发送回滚请求: “请参与者 A 和参与者 B 回滚事务。”

  2. 参与者 A 回滚本地事务: Bank A 的数据库利用 undo 日志撤销了之前的扣除操作(实际上由于余额不足,可能并没有真正扣除)。参与者 A 发送“回滚确认”。

  3. 参与者 B 回滚本地事务: Bank B 的数据库利用 undo 日志撤销了之前的增加操作(即使已经执行,也会被撤销)。参与者 B 发送“回滚确认”。

  4. 协调者收到所有“回滚确认”,事务回滚成功,保证了两个银行账户数据的一致性。

2PC 的缺点

虽然 2PC 能够保证数据的一致性,但也存在一些明显的缺点:

  • 同步阻塞 (Blocking): 在准备阶段之后,如果协调者或某个参与者发生故障,其他参与者可能会一直处于阻塞状态,等待协调者的指令或故障参与者的恢复,这会降低系统的可用性。
  • 单点故障 (Single Point of Failure): 协调者是整个事务的关键,如果协调者发生故障,整个分布式事务将无法继续进行。
  • 数据不一致的风险 (Data Inconsistency Window): 在准备阶段和提交/回滚阶段之间,如果协调者在发送提交/回滚指令前崩溃,可能会导致部分参与者提交了事务,而另一部分参与者没有,从而造成数据不一致。

TCC (Try-Confirm-Cancel) 分布式事务协议,并对比它与两阶段提交 (2PC) 的不同。

TCC:一种柔性事务

TCC 是一种基于补偿机制的分布式事务解决方案。它将一个分布式事务的生命周期划分为三个阶段:

  1. Try 阶段(尝试执行):

    • 尝试执行业务操作,完成所有业务检查(一致性)。
    • 预留必要的业务资源(准隔离性)。
    • 这个阶段的目标是尽量为后续的 Confirm 阶段准备好执行条件。
  2. Confirm 阶段(确认执行):

    • 在 Try 阶段所有参与者都成功的情况下,Confirm 阶段会被执行。
    • 真正执行业务操作,不进行任何业务检查。
    • Confirm 阶段只需要使用 Try 阶段预留的资源,因此成功率要高。
    • Confirm 操作需要保证幂等性,因为可能会重试。
  3. Cancel 阶段(取消执行):

    • 如果在 Try 阶段有任何参与者失败,或者在后续阶段发生异常,Cancel 阶段会被执行。
    • 释放 Try 阶段预留的业务资源,撤销之前 Try 阶段所做的操作,进行补偿。
    • Cancel 操作同样需要保证幂等性,因为可能会重试。

TCC 的核心思想是“先尝试,成功则确认,失败则补偿”。 它不依赖于资源管理器(如数据库)的 XA 协议,而是将事务的控制权交还给业务层面,通过业务逻辑来实现事务的提交和回滚。

一个跨银行转账的 TCC 例子

我们继续使用跨银行转账的场景:用户 A 从 Bank A 转账 100 元给用户 B 在 Bank B。

  • 参与者 A: Bank A 的转出服务。
  • 参与者 B: Bank B 的转入服务。
  • 协调者: 仍然需要一个协调者来记录事务状态和驱动流程。

Try 阶段:

  1. 协调者通知参与者 A (Try): “尝试从用户 A 账户冻结 100 元。”
  2. 参与者 A 执行 (Try): Bank A 的转出服务检查用户 A 的余额是否足够,如果足够则冻结 100 元(例如,在一个中间状态或单独的冻结金额字段中),并记录冻结日志。Try 阶段成功,返回成功。
  3. 协调者通知参与者 B (Try): “尝试在用户 B 账户预增加 100 元的额度(但尚未真正增加)。”
  4. 参与者 B 执行 (Try): Bank B 的转入服务在用户 B 的账户上预留 100 元的额度(例如,在一个中间状态或单独的待入账金额字段中),并记录预留日志。Try 阶段成功,返回成功。

Confirm 阶段(如果 Try 阶段都成功):

  1. 协调者通知参与者 A (Confirm): “确认转出操作,真正扣减用户 A 账户的 100 元。”
  2. 参与者 A 执行 (Confirm): Bank A 的转出服务从用户 A 账户的实际余额中扣除 100 元,并清除冻结记录。Confirm 成功,返回成功。
  3. 协调者通知参与者 B (Confirm): “确认转入操作,真正增加用户 B 账户的 100 元。”
  4. 参与者 B 执行 (Confirm): Bank B 的转入服务将预留的 100 元额度增加到用户 B 的实际余额中,并清除预留记录。Confirm 成功,返回成功。

Cancel 阶段(如果在 Try 阶段有失败,或后续阶段失败):

假设在 Try 阶段,Bank A 发现用户 A 余额不足,Try 失败。

  1. 协调者通知参与者 A (Cancel): “取消转出操作,释放之前冻结的金额。”
  2. 参与者 A 执行 (Cancel): Bank A 的转出服务释放之前冻结的 100 元(如果已经冻结),并清除冻结记录。Cancel 成功,返回成功。
  3. 协调者通知参与者 B (Cancel): “取消转入操作,撤销之前预增加的额度。”
  4. 参与者 B 执行 (Cancel): Bank B 的转入服务撤销之前预留的 100 元额度,并清除预留记录。Cancel 成功,返回成功。

TCC 与 2PC 的不同

特性两阶段提交 (2PC)Try-Confirm-Cancel (TCC)
协议层面依赖资源管理器(如数据库)的 XA 协议基于业务逻辑实现
资源锁定在准备阶段锁定资源,直到提交或回滚Try 阶段预留资源,Confirm/Cancel 阶段释放资源
一致性强一致性(在理想情况下)最终一致性(通过补偿机制保证)
性能可能存在长时间的资源锁定,性能相对较低资源锁定时间短,性能通常更高
可用性协调者或参与者故障可能导致长时间阻塞业务层面实现补偿,可用性相对较高
开发复杂度对业务代码侵入性较小,依赖中间件实现对业务代码侵入性较大,需要实现 Try/Confirm/Cancel 逻辑
适用场景资源支持 XA 协议的场景,对强一致性要求高的场景跨数据库、跨服务等复杂场景,对性能和可用性要求高的场景

导出到 Google 表格

总结

  • 2PC 追求强一致性,但在某些故障情况下可能导致长时间的阻塞,影响系统可用性。它依赖于底层数据库等资源管理器对 XA 协议的支持。
  • TCC 追求最终一致性,通过业务逻辑实现补偿,减少了资源锁定的时间,提高了系统的并发能力和可用性。但它对业务代码的侵入性较大,需要开发人员实现 Try、Confirm 和 Cancel 三个操作,并且要考虑幂等性、空回滚、悬挂等问题,开发复杂度较高。
XA 和 TCC 的核心区别

1. 资源层面 vs. 业务层面

  • XA (资源层面): 你可以把它想象成是由数据库(资源管理器,RM)自身提供的“官方”分布式事务解决方案。 它依赖于数据库实现了 XA 协议,这个协议定义了协调者(Transaction Manager,TM)和参与者(RM)之间如何进行两阶段提交的通信。

    • 类比: 这就像是不同银行之间有统一的国际清算系统(XA 协议),大家都遵循这个标准流程来处理跨行交易,银行内部的事务机制直接参与到这个流程中。
  • TCC (业务层面):不依赖于数据库的 XA 协议。 而是将分布式事务的控制权放在了业务代码层面。你需要自己设计每个参与服务的 Try、Confirm 和 Cancel 操作,通过编写业务逻辑来模拟两阶段提交。

    • 类比: 这就像是不同公司之间没有统一的清算系统,它们需要自己协商一套跨公司交易的流程。每个公司都需要定义“预申请”、“确认”和“撤销”这些操作的具体步骤。

2. 强一致性 vs. 最终一致性

  • XA (强一致性): 在理想情况下(没有故障),XA 能够保证严格的原子性。要么所有参与者都提交成功,要么都回滚成功,数据在事务结束后必须保持一致。

    • 理解: 就像国际清算系统保证,只要交易开始,最终要么双方账户都更新成功,要么都不更新,中间状态对用户来说是不可见的。
  • TCC (最终一致性): TCC 并不能保证在事务执行过程中所有参与者都处于完全一致的状态。如果在 Confirm 或 Cancel 阶段发生故障,可能需要进行重试人工干预来保证最终的数据一致性。它的目标是经过一段时间后,数据能够达到一致的状态。

    • 理解: 就像公司间的协商交易,如果在“确认”阶段出了问题,可能需要重新发起确认或者执行“撤销”操作,最终目标是让双方的账目对得上,但中间可能会有短暂的不一致。

3. 资源锁的处理

  • XA (长时间持有锁): 这是 XA 的一个关键特点,也是其性能瓶颈所在。在准备阶段 (Prepare),参与者(数据库)通常会锁定相关的资源(例如,数据库行、表等)。这些锁会一直保持到提交或回滚阶段结束才会释放。

    • 影响: 长时间的资源锁定会降低数据库的并发处理能力,因为其他事务可能需要等待这些锁被释放才能继续执行。
  • TCC (不长时间持有锁): TCC 的设计目标之一就是尽量缩短资源锁定的时间。

    • Try 阶段: Try 阶段通常只是预留资源(例如,冻结金额、记录中间状态),而不是直接锁定数据库的业务资源。
    • Confirm/Cancel 阶段: 这两个阶段执行真正的业务操作或补偿操作,通常只需要很短的时间,并且依赖于 Try 阶段预留的信息,不再需要长时间锁定核心业务资源。
    • 优势: 通过减少锁的持有时间,TCC 可以提高系统的并发性和吞吐量。

更形象的比喻

想象你和你的朋友合伙买一件东西,需要分别从你们的银行账户扣款:

  • XA 就像银行的联名账户: 银行提供了一个“两阶段扣款”的功能。当发起扣款时,银行会先冻结你们账户上的钱(准备阶段,持有锁),确认双方账户都冻结成功后,才会真正扣款(提交阶段,释放锁)。如果任何一方账户有问题,银行会取消冻结(回滚阶段)。这个过程由银行的系统严格控制,保证要么都扣款成功,要么都不扣款。但如果银行系统繁忙,冻结的时间可能会比较长,影响你们其他交易。

  • TCC 就像你们私下协商:

    • Try: 你先告诉银行 A:“我要给朋友转 100 元,请先帮我记录一下,这笔钱暂时不能动。”你的朋友也告诉银行 B:“我可能会收到朋友的 100 元,请先预留一个收款的记录。”(业务层面预留资源,不一定锁定核心账户余额)
    • Confirm: 如果你们都通知说“可以了,确认转账!”,银行 A 才真正扣除你的钱,银行 B 才真正增加你朋友的钱。
    • Cancel: 如果任何一方出了问题(例如,你的余额不足),你们会通知银行 A 取消之前的记录,通知银行 B 也取消之前的预留。
    • 关键: 这个过程是你们自己(业务代码)控制的,银行只是根据你们的指令操作。银行不会一直锁定你的钱,但在“确认”或“取消”失败时,可能需要你们重试或手动协调来保证最终账目正确。

总结理解的关键点

  • 谁来控制事务: XA 是资源管理器(数据库)控制,TCC 是业务代码控制。
  • 如何保证一致性: XA 依赖数据库的原子性能力,TCC 依赖业务逻辑的补偿机制。
  • 锁的持有时间: XA 持有锁的时间较长,TCC 尽量缩短锁的持有时间。
  • 适用场景: XA 适用于支持 XA 协议的同构数据源,对强一致性要求高的场景;TCC 适用于跨异构系统、需要更高并发和可用性的场景。
xa 相当于人家给我做了这个功能 而tcc则是自己实现功能?

没错 

XA 就像是数据库(或资源管理器)自身提供了“现成的”分布式事务功能。 你只需要按照 XA 协议的规范来使用,协调者会和参与者(数据库)进行通信,由数据库内部的机制来保证事务的原子性和一致性,并负责资源的锁定和释放。你更多的是在配置和使用这个“内置”的功能。

TCC 则完全是“自己动手,丰衣足食”。 你需要基于业务逻辑,自己设计和实现 Try、Confirm 和 Cancel 这三个阶段的操作。你需要考虑如何在 Try 阶段预留资源,如何在 Confirm 阶段真正执行业务操作,以及如何在 Cancel 阶段进行补偿,撤销之前的操作。TCC 将分布式事务的控制权从资源管理器转移到了业务代码层面,你需要自己编写代码来模拟两阶段提交的流程。

更进一步理解:

  • XA: 就像使用支持分布式事务的中间件(例如,某些 JMS 实现、一些分布式数据库)提供的事务管理能力。这些中间件已经帮你实现了两阶段提交的协议细节,你只需要配置和调用相应的 API。

  • TCC: 就像你需要自己编写一个复杂的业务流程,这个流程包含“预处理”、“确认执行”和“撤销处理”三个步骤,并且你需要自己保证这些步骤在分布式环境下的正确执行和数据一致性。

所以,你的总结非常精辟:

  • XA: “人家(资源管理器)给我做了这个功能,我直接用。”
  • TCC: “人家没做,我自己想办法实现这个功能。”

这种“自己实现”的灵活性使得 TCC 可以应用于 XA 无法很好解决的场景,例如跨异构数据源、不直接支持 XA 协议的服务调用等。但同时,这也带来了更高的开发复杂度和维护成本。

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

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

相关文章

数据分析-图2-图像对象设置参数与子图

from matplotlib import pyplot as mp mp.figure(A figure,facecolorgray) mp.plot([0,1],[1,2]) mp.figure(B figure,facecolorlightgray) mp.plot([1,2],[2,1]) #如果figure中标题已创建,则不会新建窗口, #而是将旧窗口设置为当前窗口 mp.figure(A fig…

跳转语句:break、continue、goto -《Go语言实战指南》

在控制流程中,我们有时需要跳出当前循环或跳过当前步骤,甚至直接跳转到指定位置。Go 提供了三种基本跳转语句: • break:跳出当前 for、switch 或 select。• continue:跳过本轮循环,进入下一轮。• goto&a…

Linux中find命令用法核心要点提炼

大家好,欢迎来到程序视点!我是你们的老朋友.小二! 以下是针对Linux中find命令用法的核心要点提炼: 基础语法结构 find [路径] [选项] [操作]路径:查找目录(.表当前目录,/表根目录)…

MQTT协议详解:物联网通信的轻量级解决方案

MQTT协议详解:物联网通信的轻量级解决方案 引言 在物联网(IoT)快速发展的今天,设备间高效可靠的通信变得至关重要。MQTT(Message Queuing Telemetry Transport)作为一种轻量级的发布/订阅协议,已成为物联网通信的首选解决方案。本文将深入探…

list基础用法

list基础用法 1.list的访问就不能用下标[]了,用迭代器2.emplace_back()几乎是与push_back()用法一致,但也有差别3.insert(),erase()的用法4.reverse()5.排序6.合并7.unique()(去重)8.splice剪切再粘贴 1.list的访问就不能用下标[]了,用迭代器…

2025年第十六届蓝桥杯大赛软件赛C/C++大学B组题解

第十六届蓝桥杯大赛软件赛C/C大学B组题解 试题A: 移动距离 问题描述 小明初始在二维平面的原点,他想前往坐标(233,666)。在移动过程中,他只能采用以下两种移动方式,并且这两种移动方式可以交替、不限次数地使用: 水平向右移动…

BGP实验练习2

需求: 1.AS1存在两个环回,一个地址为192.168.1.0/24,该地址不能再任何协议中宣告 AS3存在两个环回,该地址不能再任何协议中宣告 AS1还有一个环回地址为10.1.1.0/24,AS3另一个环回地址是11.1.1.0/24 最终要求这两…

【温湿度物联网】记录1:寄存器配置

一,及哦地址 基地址base的定义: ↓ 定义完是这个: GPIOA的地址就是以上的代表 2寄存器: 通过bsrr来改变odr寄存器,左移16位就是把0-15位的给移到高位的保留区,这样就归零了 3,项目寄存器实操…

MCP项目实例 - client sever交互

1. 项目概述 项目目标 构建一个本地智能舆论分析系统。 利用自然语言处理和多工具协作,实现用户查询意图的自动理解。 进行新闻检索、情绪分析、结构化输出和邮件推送。 系统流程 用户查询:用户输入查询请求。 提取关键词:从用户查询中…

运维体系架构规划

运维体系架构规划是一个系统性工程,旨在构建高效、稳定、安全的运维体系,保障业务系统的持续运行。下面从规划目标、核心模块、实施步骤等方面进行详细阐述: 一、规划目标 高可用性:确保业务系统 724 小时不间断运行&#xff0c…

zst-2001 上午题-历年真题 计算机网络(16个内容)

网络设备 计算机网络 - 第1题 ac 计算机网络 - 第2题 d 计算机网络 - 第3题 集线器不能隔离广播域和冲突域,所以集线器就1个广播域和冲突域 交换机就是那么的炫,可以隔离冲突域,有4给冲突域,但不能隔离广播域&#xf…

Python之with语句

文章目录 Python中的with语句详解一、基本语法二、工作原理三、文件操作中的with语句1. 基本用法2. 同时打开多个文件 四、with语句的优势五、自定义上下文管理器1. 基于类的实现2. 使用contextlib模块 六、常见应用场景七、注意事项 Python中的with语句详解 with语句是Python…

我的五周年创作纪念日

五年前的今天,我在CSDN发布了第一篇《基于VS2015的MFC学习笔记(常用按钮button)》,文末那句"欢迎交流"的忐忑留言,开启了这段充满惊喜的技术旅程。恍然发觉那些敲过的代码早已成长为参天大树。 收获 获得了…

Realtek 8126驱动分析第四篇——multi queue相关

Realtek 8126是 5G 网卡,因为和 8125 较为接近,第四篇从这里开始也无不可。本篇主要是讲 multi queue 相关,其他的一些内容在之前就已经提过,不加赘述。 1 初始化 1.1 rtl8126_init_one 从第一篇我们可以知道每个 PCI 驱动都注…

使用PHP对接日本股票市场数据

本文将介绍如何通过StockTV提供的API接口,使用PHP语言来获取并处理日本股票市场的数据。我们将以查询公司信息、查看涨跌排行榜和实时接收数据为例,展示具体的操作流程。 准备工作 首先,请确保您已经从StockTV获得了API密钥,并且…

爬虫工具与编程语言选择指南

有人问爬虫如何选择工具和编程语言。根据我多年的经验来说,是我肯定得先分析不同场景下适合的工具和语言。 如果大家不知道其他语言,比如JavaScript(Node.js)或者Go,这些在特定情况下可能更合适。比如,如果…

C语言while循环的用法(非常详细,附带实例)

while 是 C 语言中的一种循环控制结构,用于在特定条件为真时重复执行一段代码。 while 循环的语法如下: while (条件表达式) { // 循环体:条件为真时执行的代码 } 条件表达式:返回真(非 0)或假&#x…

1.短信登录

1.0 问题记录 1.0.1 redis 重复 token 问题 每次用户登录时,后端会创建一个新的 token 并存入 Redis,但之前登录的 token 还没有过期。这可能会导致以下问题: 1. Redis 中存在大量未过期但实际已不使用的 token2. 同一用户可能有多个有效 …

需求与技术实现不匹配,如何协调

协调需求与技术实现不匹配问题,需要加强技术参与需求阶段、推动架构与需求同步设计、建立跨职能沟通机制,其中加强技术参与需求阶段是最关键的一步。 需求如果脱离技术实际,就容易导致实现困难、资源浪费甚至项目失败。根据麦肯锡的一项研究&…

java每日精进 5.11【WebSocket】

1.纯Websocket实现消息发送 1.1一对一发送 前端 用户在输入框输入消息内容(sendText) 选择特定接收用户(sendUserId) 点击发送按钮触发handlerSend方法 构造消息内容JSON: {text: "Hello", // 消息内容toUserId: 123 // 目标用户ID } 包装为WebSocket标准格式…