RabbitMQ 实现简易即时通讯

server/2024/12/22 18:44:00/

设计思路

利用消息队列的特性进行消息投递,假设客户端 A 要与客户端 B 进行通信。
客户端 A :创建队列 A-B ,发送的消息推送到 A-B 队列, 绑定 B-A 队列,接收 B-A 队列推送给客户端的消息。
客户端 B :创建队列 B-A ,发送的消息推送到 B-A 队列, 绑定 A-B 队列,接收 A-B 队列推送给客户端的消息。

如果其中某个客户端主动退出或者异常中断时,销毁队列 A-B 以及队列 B-A(是否销毁视实际应用场景来定)。

实现

创建RabbitMQ 工具类,用以获取连接及销毁队列。

import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;import java.io.IOException;
import java.util.concurrent.TimeoutException;public class ClientUtils {private static ConnectionFactory DEFAULT_FACTORY_INSTANCE = null;static {DEFAULT_FACTORY_INSTANCE = new ConnectionFactory();DEFAULT_FACTORY_INSTANCE.setHost("127.0.0.1");DEFAULT_FACTORY_INSTANCE.setUsername("user");DEFAULT_FACTORY_INSTANCE.setPassword("123456");DEFAULT_FACTORY_INSTANCE.setVirtualHost("testVirtualHost");}public static Connection getConnection() throws IOException, TimeoutException {return DEFAULT_FACTORY_INSTANCE.newConnection();}public static void queueDelete(Channel channel, String queue) throws IOException {channel.queueDelete(queue);}public static void queueDelete(Channel channel, String... queues) throws IOException {for (int i = 0; i < queues.length; i++) {channel.queueDelete(queues[i]);}}}

创建聊天客户端核心类,用于处理消息发送逻辑以及消息接收逻辑。


import com.rabbitmq.client.CancelCallback;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.DeliverCallback;
import org.springframework.util.StringUtils;import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.concurrent.TimeoutException;/*** 需保证 send 与 reciver 的值是唯一的*/public class ChatClient {private String send;private String reciver;public ChatClient(String send, String reciver) {this.send = send;this.reciver = reciver;}public void start() {try (Channel channel = ClientUtils.getConnection().createChannel();Scanner scanner = new Scanner(System.in);) {String pub = send + "-" + reciver;String rec = reciver + "-" + send;channel.queueDeclare(pub, false, false, false, null);channel.queueDeclare(rec, false, false, false, null);System.out.println(String.format("%s连接到%s", send, reciver));String message = null;while (true) {//接收到信息回调接口,目的是当接收到一条信息时,进行一些操作,比如可以在控制台里打印出来DeliverCallback deliverCallback = (consumerTag, delivery) -> {//todo 这里可以做一个消息类型的识别,使用策略模式不同类型使用不同的解析器String receiveMessage = new String(delivery.getBody(), "UTF-8");System.out.println(String.format("收到%s消息:%s", rec, receiveMessage));};//取消接收的回调接口,目的是如在接收消息的时候队列被删除掉了,可以进行一些操作。CancelCallback cancelCallback = (consumerTag) -> {System.out.println("消息中断");ClientUtils.queueDelete(channel, pub, rec);//退出System.exit(0);};//管道接收消息channel.basicConsume(rec, true, deliverCallback, cancelCallback);if ((message = scanner.nextLine()) != null && StringUtils.hasText(message)) {if ("exit".equals(message)) {System.out.println("终止发送消息");ClientUtils.queueDelete(channel, pub, rec);System.exit(0);break;}// todo 对发送的消息进行转换,以支持更多的类型channel.basicPublish("", pub, null, message.getBytes());System.out.println(String.format("%s发送消息:%s", pub, message));message = null;}}} catch (Exception e) {e.printStackTrace();}}
}

实现客户端 A

public class Client1 {public static void main(String[] args) {ChatClient client = new ChatClient("A", "B");client.start();}
}

实现客户端 B

public class Client2 {public static void main(String[] args) {ChatClient client = new ChatClient("B", "A");client.start();}
}

测试

客户端 A 上线,发送消息,此时客户端 B 未上线。

在这里插入图片描述

由于此时客户端 B 还未上线,消息会积压在RabbitMQ队列中,等待客户端 B 上线消费。

在这里插入图片描述

客户端 B 上线,消费积压在MQ的消息。

在这里插入图片描述

此时客户端 A 与客户端 B 同时在线,可以进行即时通信。

小结

这里只是讲述了文本消息的传递,输入内容也是使用控制台输入。实际上可以拓展到其它类型,比如图片,音频等,只需要统一消息体,在消息发送及接收时进行消息的封装和解析。

比如,发送图片消息时可以标识此条消息为图片类型,然后将图片转换为二进制文本,封装成一个完整的消息投递。客户端接收到的消息根据消息投递的类型使用不同的解析器去进行解析。


http://www.ppmy.cn/server/61103.html

相关文章

CSS 【详解】CSS 函数(含 calc,min,max,clamp,cubic-bezier,env,steps 等)

函数描述CSS 版本attr()返回选择元素的属性值。2calc()允许计算 CSS 的属性值&#xff0c;比如动态计算长度值。3cubic-bezier()定义了一个贝塞尔曲线(Cubic Bezier)。3hsl()使用色相、饱和度、亮度来定义颜色。3hsla()使用色相、饱和度、亮度、透明度来定义颜色。3linear-grad…

[PaddlePaddle飞桨] PaddleOCR-光学字符识别-小模型部署

PaddleOCR的GitHub项目地址 推荐环境&#xff1a; PaddlePaddle > 2.1.2 Python > 3.7 CUDA > 10.1 CUDNN > 7.6pip下载指令&#xff1a; python -m pip install paddlepaddle-gpu2.5.1 -i https://pypi.tuna.tsinghua.edu.cn/simple pip install paddleocr2.7…

大模型/NLP/算法面试题总结7——LLaMA和别的模型架构有什么区别

LLaMA&#xff08;Large Language Model Meta AI&#xff09;与其他模型架构的区别主要体现在其设计思想、技术细节和应用场景上。 以下是对LLaMA模型架构特点的详细分析&#xff0c;以及与其他模型架构的对比&#xff1a; 一、设计思想 LLaMA&#xff1a; 强调在给定计算预…

Android知识收集

文章列表 Android 高版本 HTTPS 抓包解决方案&#xff01;链接关于RecyclerView你知道的不知道的都在这了 链接 工具列表 抓包工具-Reqable下载. 链接阿里云云效Maven 链接Android各尺寸图标生成 链接App Icon Generator&#xff0c;图标生成支持android&#xff0c; ios 链…

全方位指南,电子期刊制作入门到精通

在这个数字化时代&#xff0c;电子期刊作为一种新兴的媒体形式&#xff0c;以其方便快捷、互动性强、传播范围广等特点&#xff0c;受到越来越多人的青睐。那么&#xff0c;如何制作出一本既专业又有吸引力的电子期刊呢&#xff1f; 一、选择合适的制作软件 首先&#xff0c;选…

2024年7月9日~2024年7月15日周报

目录 一、前言 二、完成情况 2.1 特征图保存方法 2.1.1 定义网络模型 2.1.2 定义保存特征图的钩子函数 2.1.3 为模型层注册钩子 2.1.4 运行模型并检查特征图 2.2 实验情况 三、下周计划 一、前言 本周的7月11日~7月14日参加了机器培训的学习讨论会&#xff0c;对很多概…

git为文件添加可执行权限

查看文件权限 git ls-files --stage .\SecretFinder.py100644 表示文件的所有者有读取和写入权限 添加可执行权限 git update-index --chmod x .\SecretFinder.py再次查看文件权限 git ls-files --stage .\SecretFinder.py100755 表示文件的所有者有读取、写入和执行权限

Python与自动化脚本编写

Python与自动化脚本编写 Python因其简洁的语法和强大的库支持&#xff0c;成为了自动化脚本编写的首选语言之一。在这篇文章中&#xff0c;我们将探索如何使用Python来编写自动化脚本&#xff0c;以简化日常任务。 一、Python自动化脚本的基础 1. Python在自动化中的优势 Pyth…