消息队列Rabbitmq
消息队列 软件--Rabbitmq
解释:
生产者将消息发送到队列,消费者从队列中获取消息。
多个客户端向服务端同时发送信息,防止服务器崩溃,把客户端发送的信息先放入消息队列中,再由消息队列依次发送到服务端,防止并发引发服务器崩溃
一、Docker安装Rabbitmq
参考:csdn文档有教程
我此时云服务器用的腾讯云
https://blog.csdn.net/WLPJLP/article/details/125449712
Rabbitmq是最常用的消息队列软件,经常用于流量削峰、异步事务、系统解耦、日志处理等等。
---参考word云服务器安装Rabbitmq后测试一下

登录时后有误

解决:
3、云服务器(腾讯云)配置防火墙 --设置端口号 (暂时需要配置两个)--必须配置好这个后才可以有上面那种登录页面的显示效果
(12条消息) 消息中间件RabbitMQ需要知道的6个端口的作用_像夏天一样热的博客-CSDN博客_rabbitmq 各个端口

二、.Net Core 引入消息队列
.NetCore中使用RabbitMQ
参考:
https://blog.csdn.net/m0_54852350/article/details/124501873
https://blog.csdn.net/qq_38284923/article/details/119675498
https://www.cnblogs.com/yan7/p/9498685.html
.Net Core 使用CAP框架实现异步化分布式事务
https://blog.csdn.net/qq_26900081/article/details/108509324
https://cap.dotnetcore.xyz/user-guide/zh/getting-started/quick-start/
1、Program中注册RabbitMq

//使用CAP 来注册RabbitMq //引用nuget包 DotNetCore.CAP.RabbitMQ和DotNetCore.CAP.MySql // CAP 是一个EventBus,同时也是一个在微服务或者SOA系统中解决分布式事务问题的一个框架。它有助于创建可扩展,可靠并且易于更改的微服务系统。 //https://cap.dotnetcore.xyz/user-guide/zh/getting-started/introduction/ var configuration = builder.Configuration; builder.Services.AddCap(x => { // 8.2 使用mysql进行事务处理,防止推送MQ失败,会在指定数据库中自动生成以"cap."开头的表 x.UseMySql(connection); // 8.3 使用RabbitMQ进行事件中心处理 x.UseRabbitMQ(option => { option.HostName = configuration["CAPRabbitMQ:HostName"]; string portStr = configuration["CAPRabbitMQ:Port"]; if (!string.IsNullOrEmpty(portStr)) { option.Port = Convert.ToInt32(portStr); } // option.VirtualHost = configuration["CAPRabbitMQ:VirtualHost"]; option.UserName = configuration["CAPRabbitMQ:UserName"]; option.Password = configuration["CAPRabbitMQ:Password"]; //if (!string.IsNullOrEmpty(configuration["CAPRabbitMQ:ExchangeName"])) //{ // option.ExchangeName = configuration["CAPRabbitMQ:ExchangeName"]; //} //option.ConnectionFactoryOptions = factory => factory.AutomaticRecoveryEnabled = true; }); //// 设置处理成功的数据在数据库中保存的时间(秒),为了保证系统性能,数据会定期清理 //x.SucceedMessageExpiredAfter = Convert.ToInt32(configuration["CAPRabbitMQ:SucceedMessageExpiredAfter"]); //// 重试次数 //x.FailedRetryCount = Convert.ToInt32(configuration["CAPRabbitMQ:FailedRetryCount"]); //// 间隔时间 单位:秒 //x.FailedRetryInterval = Convert.ToInt32(configuration["CAPRabbitMQ:FailedRetryInterval"]); //发送消息失败后的回调 x.FailedThresholdCallback = (failedInfo) => { Log4Tools log = new Log4Tools(); log.InfoObj($"消息队列出现错误:{failedInfo}"); }; // x.Version = configuration["CAPRabbitMQ:Version"]; });
②步骤对应数据库会自动生成了cap开头的表

2、配置文件里加入一系列http路径、端口号一系列配置
(放在了appsettings.json文件进行配置了,因为无论开发状态还是发布状态下都是用云主机上面的这个RabbitMQ)

"CAPRabbitMQ": { "HostName": "云主机Ip",//多个逗号隔开 "Port": 5601, "UserName": "rbmq", "Password": "YHUasd#$%45", "VirtualHost": "mess_manager", //虚拟消息服务器 类似于mysql表 参考https://blog.csdn.net/h996666/article/details/83304626 "ExchangeName": "scp.exchange", //交换机.v3 "FailedRetryCount": 5, //失败重试次数 "FailedRetryInterval": 3, // 失败重试间隔时间 单位:秒 "Version": "v1", "SucceedMessageExpiredAfter": 1440 // 定期清理成功的数据,单位分钟 },
不加这个会有错

3、创建Model用于往MongoDb中存入信息--类似于查看聊天记录
public class SignalRMessage { /// <summary> /// mongodb 主键id /// </summary> public ObjectId id { get; set; } /// <summary> /// signal 连接id /// </summary> public string? conn_id { get; set; } /// <summary> /// 发起人 /// </summary> public string? send_user { get; set; } /// <summary> /// 接受人 /// </summary> public string get_user { get; set; } /// <summary> /// 标题 /// </summary> public string title { get; set; } /// <summary> /// 内容 /// </summary> public string content { get; set; } /// <summary> /// 发送时间 /// </summary> public DateTime? send_date { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime? created_date { get; set; } }
修改上一博客的SignalR的model,加一个连接SignalR的Id的conn_id字符串
//SignalR用的Mdoel public class SignalRMessageViewModel { /// <summary> /// 发起人 /// </summary> public string? send_user { get; set; } /// <summary> /// signal 连接id /// </summary> public string? conn_id { get; set; } /// <summary> /// 接受人 /// </summary> public string get_user { get; set; } /// <summary> /// 标题 /// </summary> public string title { get; set; } /// <summary> /// 内容 /// </summary> public string content { get; set; } /// <summary> /// 发送时间 /// </summary> public DateTime? send_date { get; set; } /// <summary> /// 创建时间 /// </summary> public DateTime? created_date { get; set; } }
并且必须也要加上public ObjectId id { get; set; }字段--否则显示Mongodb数据时候报错

/// <summary> /// mongodb 主键id /// </summary> public ObjectId id { get; set; }
4、更新修改上一博客实现signalR推送消息创建连接初始化那里(SystemMessageHub类中)

5、在上一博客实现signalR推送消息中发送消息的控制器处加入实现消息队列

public class MessManagerController :BaseMessConterController { private readonly IHubContext<SystemMessageHub> systemMessageHub; //事件总线 private readonly ICapPublisher _capBus; private readonly systemConterMessService _systemConterMessService; /// <summary> /// 注入signalr 的消息推送的hub /// </summary> /// <param name="systemMessageHub"></param> public MessManagerController(IHubContext<SystemMessageHub> systemMessageHub, ICapPublisher _capBus, systemConterMessService _systemConterMessServices) { this.systemMessageHub = systemMessageHub; this._capBus = _capBus; _systemConterMessService = _systemConterMessServices; } /// <summary> /// 发送消息的接口 /// </summary> /// <param name="message">要发送的消息</param> /// <returns></returns> [HttpPost] public async Task<ResultModel<bool>> SendMess(SignalRMessageViewModel message) { ////如果接口人是all 代表给所有人都发送 //if (message.get_user == "all") //{ // // 给所有客户端发送消息 message 表示给客户端传递的参数 // systemMessageHub.Clients.All.SendAsync("GetAllMess", message); //} //return MyOk<bool>(true); try { message.send_user = LoginInfo.operator_name; message.send_date = DateTime.Now; _capBus.Publish("GroupThreeObject01sysmess.usermess", message); //将要发送的消息存入消息队列 return MyOk(true); } catch (Exception ex) { return MyError<bool>(ex); } } /// <summary> /// 监听,并获取 sysmess.usermess 的消息队列的消息 /// </summary> /// <param name="MessageDto"></param> /// <returns></returns> /// [NonAction]表示在控制器中他不是一个请求 /// [CapSubscribe("sysmess.usermess")]发到消息对列后,这个方法加这个就会由消息队列转到这里 [NonAction] [CapSubscribe("GroupThreeObject01sysmess.usermess")] public async Task CheckReceivedMessage(SignalRMessageViewModel message) { //把发送数据存入Mongodb中--聊天记录保存 _systemConterMessService.SystemConterMessAdd(message); //如果接收入人是all 代表给所有人都发送 if (message.get_user == "all") { //给所有客户端发送消息 message 表示给客户端传递的参数 使用singnal往外推消息 systemMessageHub.Clients.All.SendAsync("GetAllMess", message); } //否则发送给指定人 else { if (string.IsNullOrEmpty(message.conn_id)) { //用户名获取连接id message.conn_id = SystemMessageHub.GetConnIdByUserName(message.get_user); } if (!string.IsNullOrEmpty(message.conn_id)) //通过SingnalR推送消息 systemMessageHub.Clients.Clients(message.conn_id).SendAsync("GetAllMess", message); } } /// <summary> /// 获取此系统登录的用户列表 /// </summary> /// <param name="userName"></param> /// <returns></returns> [HttpGet] public async Task<ResultModel<object>> GetMessUsers(string? userName) { IEnumerable<KeyValuePair<string, UserData>> di; //每一次登录都会加入SystemMessageHub声明那个字典里保存对应登录信息 if (!string.IsNullOrEmpty(userName)) { di = SystemMessageHub.UserIdAndCid.Where(c => c.Key.Contains(userName)); } else { di = SystemMessageHub.UserIdAndCid; } var result = di.Select(c => new { user_name = c.Value.UserName, pwd=c.Value.Pwd }) .GroupBy(d => d.user_name) .Select(e => new { user_name = e.Key, pwd = e.Select(f => f.pwd).FirstOrDefault() }) .ToList(); return MyOk<object>(result); } /// <summary> //获取mogodb数据,显示聊天记录 /// </summary> /// <param name="searchModel"></param> /// <returns></returns> [HttpPost] public async Task<ResultModel<PagingModel<SignalRMessageViewModel>>> SearchMessagePage(SearchModel searchModel) { return MyOk(_systemConterMessService.SearchSystemMess(searchModel)); } }
6、在SystemMessageHub类编写根据用户名获取到他的连接SignalR的连接ID

/// <summary> /// 根据userName获取连接id /// </summary> /// <param name="userName">用户名</param> /// <returns></returns> public static string GetConnIdByUserName(string userName) { if (UserIdAndCid.Keys.Contains(userName)) { return UserIdAndCid[userName].ConnectionId; } return ""; }
7、仿照SignalR测试方式--可以实现给指定人发送消息
本文来自博客园,作者:じ逐梦,转载请注明原文链接:https://www.cnblogs.com/ZhuMeng-Chao/p/16478000.html

浙公网安备 33010602011771号