feat: initial commit - HJHA game server full source
6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) + game logic (GameFix/GameDAL/ServerData) + network layer (NetWorkMessage) + data layer (ObjectModel) + utilities (MrWu/Core/Config/CloudAPI/dll) + adapters (zyxAdapter/base) .NET 8.0 C# solution, 16 projects, 958 source files
This commit is contained in:
23
GlobalSever/MQ/DeliveryResult.cs
Normal file
23
GlobalSever/MQ/DeliveryResult.cs
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 由SharpDevelop创建。
|
||||
* 用户: Administrator
|
||||
* 日期: 2018-12-22
|
||||
* 时间: 13:56
|
||||
*
|
||||
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
|
||||
*/
|
||||
using System;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// 投递结果
|
||||
/// </summary>
|
||||
public class DeliveryResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 0表示没有找到这个模块 1表示投递成功 2表示投递失败
|
||||
/// </summary>
|
||||
public int style;
|
||||
}
|
||||
}
|
||||
112
GlobalSever/MQ/GameFilter.cs
Normal file
112
GlobalSever/MQ/GameFilter.cs
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 由SharpDevelop创建。
|
||||
* 用户: Administrator
|
||||
* 日期: 2018-10-30
|
||||
* 时间: 16:00
|
||||
*
|
||||
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
|
||||
*/
|
||||
|
||||
using System;
|
||||
using GameData;
|
||||
using MrWu.Debug;
|
||||
using MrWu.RabbitMQ;
|
||||
using Server.Pack;
|
||||
|
||||
namespace Server.MQ {
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class GameFilter : IMQFilter {
|
||||
string IMQFilter.Name {
|
||||
get {
|
||||
return "GameFilter";
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public Action<PackHead, string> SocketMessageHandler {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public readonly ServerNode myUtil;
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="socketMessageHandler"></param>
|
||||
/// <param name="myUtil"></param>
|
||||
public GameFilter(Action<PackHead, string> socketMessageHandler, ServerNode myUtil) {
|
||||
SocketMessageHandler = socketMessageHandler;
|
||||
this.myUtil = myUtil;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
public bool Filter(Message message, Recv2ReturnDescription msgDesc) {
|
||||
var jsondata = JsonPack.GetPackHead(message.bodystr, out PackHead head);
|
||||
if (head == null)
|
||||
return false;
|
||||
if (myUtil.Equals(head.gameNode)) { //是本游戏 直接发送
|
||||
return true;
|
||||
} else { //不是本游戏 转发给别的Socket
|
||||
Debug.Error("这个包没带游戏标志:" + head.packlx);
|
||||
return false;
|
||||
}
|
||||
//return head?.packlx == GamePackAgreement.TransFerPack;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
public object HandleMessage(Message message, Recv2ReturnDescription msgDesc) {
|
||||
var jsondata = JsonPack.GetPackHead(message.bodystr, out PackHead head);
|
||||
head.packlx = head.transfer;
|
||||
SocketMessageHandler(head, jsondata);
|
||||
return null;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
public bool CallFilter(string msg, Recv2ReturnDescription msgDesc) {
|
||||
return false;
|
||||
}
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
public object HandleCallMessage(string msg, Recv2ReturnDescription msgDesc) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public bool FilterCallback(Message message) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
public void HandleCallbackMessage(Message message) {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
1359
GlobalSever/MQ/GlobalMQ.cs
Normal file
1359
GlobalSever/MQ/GlobalMQ.cs
Normal file
@ -0,0 +1,1359 @@
|
||||
/*
|
||||
* 由SharpDevelop创建。
|
||||
* 用户: Administrator
|
||||
* 日期: 2018-10-30
|
||||
* 时间: 16:00
|
||||
*
|
||||
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameData;
|
||||
using GameDAL;
|
||||
using MrWu.Debug;
|
||||
using MrWu.RabbitMQ;
|
||||
using RabbitMQ.Client;
|
||||
using Server.Data.Module;
|
||||
using Server.Module;
|
||||
using Server.MQ;
|
||||
using Server.Pack;
|
||||
|
||||
namespace Server.MQ
|
||||
{
|
||||
/*
|
||||
* 设计方案
|
||||
*
|
||||
* exit_game_1 : 提示玩家网络故障,踢出玩家所在的游戏
|
||||
*
|
||||
*
|
||||
*
|
||||
* */
|
||||
|
||||
/// <summary>
|
||||
/// 消息管理 工厂
|
||||
/// </summary>
|
||||
public abstract class IGlobalFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建消息管理
|
||||
/// </summary>
|
||||
public abstract void CreateGlobalMQ();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rabbit消息投递管理类
|
||||
/// </summary>
|
||||
public class GlobalMQ : IGlobalMQ
|
||||
{
|
||||
/// <summary>
|
||||
/// 消息管理工厂
|
||||
/// </summary>
|
||||
public class Factory : IGlobalFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// 创建消息管理类
|
||||
/// </summary>
|
||||
public override void CreateGlobalMQ()
|
||||
{
|
||||
if (instance == null)
|
||||
instance = new GlobalMQ();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// rabbit消息投递管理类单例
|
||||
/// </summary>
|
||||
public static GlobalMQ instance { get; protected set; }
|
||||
|
||||
/// <summary>
|
||||
/// 失败原因的 key 消息未发送成功(502) 消息未被路由(503) 消息被扔弃(504)
|
||||
/// </summary>
|
||||
public const string failCode = "failCode";
|
||||
|
||||
/// <summary>
|
||||
/// 应该由谁来处理这个未被路由或被扔弃的包
|
||||
/// </summary>
|
||||
public const string doFailKey = "doFail";
|
||||
|
||||
/// <summary>
|
||||
/// 应该由哪个节点来处理扔弃的包
|
||||
/// </summary>
|
||||
public const string doFailNodeNum = "doFailNodeNum";
|
||||
|
||||
/// <summary>
|
||||
/// 处理失败的标记-有标记的才会处理,没有的会被扔弃
|
||||
/// </summary>
|
||||
public const string failTagKey = "failTag";
|
||||
|
||||
/// <summary>
|
||||
/// 发送成功要做的事
|
||||
/// </summary>
|
||||
public const string successTagKey = "successTag";
|
||||
|
||||
/// <summary>
|
||||
/// 构造
|
||||
/// </summary>
|
||||
protected GlobalMQ()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息管理
|
||||
/// </summary>
|
||||
protected RabbitManager rabbit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// rpc客户端
|
||||
/// </summary>
|
||||
public RpcClient rpcClient { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetNoAckCount()
|
||||
{
|
||||
if (rabbit == null)
|
||||
return 0;
|
||||
return rabbit.NoAckCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送完成事件
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public virtual bool SendOK(Message msg)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送失败
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public virtual void SendFail(Message msg)
|
||||
{
|
||||
return;
|
||||
if (msg.userData == null || !msg.userData.ContainsKey(failCode)
|
||||
|| !msg.userData.ContainsKey(failTagKey) || !msg.userData.ContainsKey(doFailKey))
|
||||
{
|
||||
if (!msg.noAck && msg.deliveryTag > 0)
|
||||
msg.Ack();
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
string dofailTag = msg.userData[failTagKey].ToString();
|
||||
|
||||
//switch(dofailTag){
|
||||
|
||||
// };
|
||||
msg.Ack();
|
||||
Debug.Log("处理发送失败的消息:" + dofailTag + "," + msg);
|
||||
return;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("处理发送失败消息时出现错误,msg:{0},exception:{1}", msg, e.ToString());
|
||||
msg.NAck();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 链接阻塞
|
||||
/// </summary>
|
||||
public void ConnectionBlocked()
|
||||
{
|
||||
//if (rabbit == null)
|
||||
// return;
|
||||
//rabbit.ConnectionBlocked();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 解除链接阻塞
|
||||
/// </summary>
|
||||
public void ConnectionUnBlocked()
|
||||
{
|
||||
//if (rabbit == null)
|
||||
// return;
|
||||
//rabbit.ConnectionUnBlocked();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
public virtual void SendMessage(Message msg, bool isAutoFree)
|
||||
{
|
||||
//CheckFiltersAndPublishNoReturn(rabbit.BasicPublish, msg, isAutoFree, Recv2ReturnDescription.One_Void);//
|
||||
rabbit.BasicPublish(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息并要得到发送结果
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
///<param name="isAutoFree">是否自动释放</param>
|
||||
public virtual bool SendMessage_Result(Message msg, bool isAutoFree)
|
||||
{
|
||||
// return CheckFiltersAndPublish(rabbit.BasicPublish_Result, msg, isAutoFree, Recv2ReturnDescription.One_Bool);//
|
||||
return rabbit.BasicPublish_Result(msg, isAutoFree);
|
||||
}
|
||||
|
||||
private ModuleUtile myUtile;
|
||||
|
||||
/// <summary>
|
||||
/// rabbit消息管理启动
|
||||
/// </summary>
|
||||
/// <param name="config">rabbit配置</param>
|
||||
/// <param name="utile">模块</param>
|
||||
/// <param name="DelExists">是否删除已存在的路由,大升级要使用到,路由规则已改</param>
|
||||
/// <returns>启动成功还是失败</returns>
|
||||
public bool StartModule(RabbitConfig config, ModuleUtile utile, bool DelExists = false)
|
||||
{
|
||||
if (rabbit != null)
|
||||
return false;
|
||||
|
||||
myUtile = utile;
|
||||
RountingManager.instance.Start((ModuleType)myUtile.id, myUtile.nodeNum);
|
||||
AddConfig(config, utile, DelExists);
|
||||
rabbit = new RabbitManager();
|
||||
|
||||
rabbit.SendResult += SendResult;
|
||||
rabbit.notRoutingOk += NotRoutingOk;
|
||||
rabbit.Start(config);
|
||||
|
||||
rpcClient = rabbit.CreateRpcClient();
|
||||
|
||||
CreateConsumer();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加配置
|
||||
/// </summary>
|
||||
/// <param name="config">配置</param>
|
||||
/// <param name="utile">当前模块</param>
|
||||
/// <param name="delExists">是否声明前先删除模块</param>
|
||||
public virtual void AddConfig(RabbitConfig config, ModuleUtile utile, bool delExists)
|
||||
{
|
||||
string exbak = "Expired"; //过期的交换机 过期的队列
|
||||
|
||||
ExchangeInfo[] exchangeInfos = new ExchangeInfo[3];
|
||||
ExchangeInfo info = new ExchangeInfo();
|
||||
info.name = RountingManager.instance.clubsterRouteName;
|
||||
info.type = "topic";
|
||||
info.durable = true;
|
||||
info.autodelete = false;
|
||||
info.delExists = delExists;
|
||||
// info.alternate_exchange = exbak;
|
||||
|
||||
exchangeInfos[0] = info;
|
||||
|
||||
info = new ExchangeInfo();
|
||||
info.name = RountingManager.instance.clusterAllRouteName;
|
||||
info.type = "fanout";
|
||||
info.durable = true;
|
||||
info.autodelete = false;
|
||||
info.delExists = delExists;
|
||||
// info.alternate_exchange = exbak;
|
||||
|
||||
exchangeInfos[1] = info;
|
||||
|
||||
info = new ExchangeInfo();
|
||||
info.name = RountingManager.instance.clusterNodeOne;
|
||||
info.type = "direct";
|
||||
info.durable = true;
|
||||
info.autodelete = false;
|
||||
info.delExists = delExists;
|
||||
// info.alternate_exchange = exbak;
|
||||
|
||||
exchangeInfos[2] = info;
|
||||
|
||||
config.exchanges = exchangeInfos;
|
||||
|
||||
QueueInfo[] queueinfos = new QueueInfo[2];
|
||||
QueueInfo queue = new QueueInfo();
|
||||
queue.name = RountingManager.instance.queueNode;
|
||||
queue.durable = true;
|
||||
queue.exclusive = false;
|
||||
queue.startClear = false;
|
||||
queue.delExists = delExists;
|
||||
queue.autodelete = false;
|
||||
queue.x_message_ttl = 0;
|
||||
// queue.x_dead_letter_exchange = exbak;
|
||||
// queue.x_dead_routing_key = "expire";
|
||||
queueinfos[0] = queue;
|
||||
|
||||
queue = new QueueInfo();
|
||||
queue.name = RountingManager.instance.queueEveryOne;
|
||||
queue.durable = true;
|
||||
queue.exclusive = false;
|
||||
queue.startClear = false;
|
||||
queue.delExists = delExists;
|
||||
queue.autodelete = false;
|
||||
queue.x_message_ttl = 0;
|
||||
// queue.x_dead_letter_exchange = exbak;
|
||||
// queue.x_dead_routing_key = "expire";
|
||||
queueinfos[1] = queue;
|
||||
|
||||
config.queues = queueinfos;
|
||||
|
||||
BindInfo[] bindInfos = new BindInfo[6];
|
||||
BindInfo bindInfo = new BindInfo();
|
||||
bindInfo.destination = RountingManager.instance.queueNode;
|
||||
bindInfo.source = RountingManager.instance.clusterAllRouteName;
|
||||
bindInfo.routingkey = RountingManager.instance.routeallkey;
|
||||
bindInfo.bindType = "queue";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[0] = bindInfo;
|
||||
|
||||
bindInfo = new BindInfo();
|
||||
bindInfo.destination = RountingManager.instance.queueNode;
|
||||
bindInfo.source = RountingManager.instance.clusterNodeOne;
|
||||
bindInfo.routingkey = RountingManager.instance.nodeRouteKey;
|
||||
bindInfo.bindType = "queue";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[1] = bindInfo;
|
||||
|
||||
bindInfo = new BindInfo();
|
||||
bindInfo.destination = RountingManager.instance.queueEveryOne;
|
||||
bindInfo.source = RountingManager.instance.clubsterRouteName;
|
||||
bindInfo.routingkey = RountingManager.instance.routeEveryOneKey;
|
||||
bindInfo.bindType = "queue";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[2] = bindInfo;
|
||||
|
||||
bindInfo = new BindInfo();
|
||||
bindInfo.destination = RountingManager.instance.clubsterRouteName;
|
||||
bindInfo.source = RountingManager.AllServerRouteName;
|
||||
bindInfo.routingkey = RountingManager.instance.routeallkey;
|
||||
bindInfo.bindType = "exchange";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[3] = bindInfo;
|
||||
|
||||
bindInfo = new BindInfo();
|
||||
bindInfo.destination = RountingManager.instance.clusterAllRouteName;
|
||||
bindInfo.source = RountingManager.instance.clubsterRouteName;
|
||||
bindInfo.routingkey = RountingManager.instance.routeallkey;
|
||||
bindInfo.bindType = "exchange";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[4] = bindInfo;
|
||||
|
||||
bindInfo = new BindInfo();
|
||||
|
||||
bindInfo.destination = RountingManager.instance.clusterNodeOne;
|
||||
bindInfo.source = RountingManager.instance.clubsterRouteName;
|
||||
bindInfo.routingkey = RountingManager.instance.nodeRouteMatch;
|
||||
bindInfo.bindType = "exchange";
|
||||
|
||||
Debug.Info("绑定信息,目标:" + bindInfo.destination + ",源:" + bindInfo.source + ",路由键:" + bindInfo.routingkey);
|
||||
|
||||
bindInfos[5] = bindInfo;
|
||||
|
||||
config.binds = bindInfos;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否开启接收消息日志
|
||||
/// </summary>
|
||||
public static bool openMsgLog;
|
||||
|
||||
/// <summary>
|
||||
/// 接收到消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public virtual void ReciveMessage(Message msg)
|
||||
{
|
||||
if (openMsgLog)
|
||||
Debug.Log("接收到消息:" + msg.ToString());
|
||||
|
||||
if (msg.userData != null && msg.userData.ContainsKey(failCode))
|
||||
{
|
||||
//有错误信息的消息,处理错误
|
||||
SendFail(msg);
|
||||
MessagePool.PutMessage(ref msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
//正常收包
|
||||
AddMessage(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 未被路由的消息 事件过来的
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
protected void NotRoutingOk(Message msg)
|
||||
{
|
||||
return;
|
||||
DoFail(msg, 503);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分发处理失败的消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="FailCode"></param>
|
||||
protected void DoFail(Message msg, int FailCode)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!msg.userData.ContainsKey(failTagKey)) //没有标记不处理
|
||||
return;
|
||||
if (msg.userData.ContainsKey(failCode))
|
||||
{
|
||||
//已经有错误标记,说明已经进入了此流程-并投递给别人使用,当时又出了问题避免死循环不再处理,记录日志
|
||||
Debug.Error("消息发送失败,并未被处理.failCode:{0},msg:{1}", msg.userData[failCode], msg);
|
||||
return;
|
||||
}
|
||||
|
||||
//先赋值失败原因 未发送成功
|
||||
msg.userData[failCode] = FailCode;
|
||||
|
||||
bool isMyFail = false;
|
||||
|
||||
if (msg.userData.ContainsKey(doFailKey))
|
||||
{
|
||||
//没赋值处理失败的人就是自己处理
|
||||
object tmp = msg.userData[doFailKey];
|
||||
int id = (int)tmp;
|
||||
if (id == myUtile.id)
|
||||
{
|
||||
//是本模块处理的
|
||||
|
||||
if (msg.userData.ContainsKey(doFailNodeNum))
|
||||
{
|
||||
//如果指定了处理的节点
|
||||
int nodenum = (int)msg.userData[doFailNodeNum];
|
||||
if (nodenum == myUtile.id)
|
||||
isMyFail = true;
|
||||
}
|
||||
else
|
||||
isMyFail = true;
|
||||
|
||||
if (isMyFail) //处理发送失败的错误
|
||||
SendFail(msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isMyFail)
|
||||
{
|
||||
//投递给处理失败的模块队列
|
||||
//待补待补
|
||||
|
||||
//处理错误模块的id
|
||||
int nodeid = (int)msg.userData[doFailKey];
|
||||
|
||||
bool isNAck = false;
|
||||
|
||||
if (msg.userData.ContainsKey(doFailNodeNum))
|
||||
{
|
||||
//指定了节点-投递给指定节点
|
||||
int nodenum = (int)msg.userData[doFailNodeNum];
|
||||
msg.SendResult = null;
|
||||
if (!DeliveryOne_Result(new ServerNode(nodeid, nodenum), msg, false))
|
||||
{
|
||||
//发不出去就拒收,下次再处理
|
||||
isNAck = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//没指定节点,投递给任意节点
|
||||
msg.SendResult = null;
|
||||
if (!DeliveryEveryOne_Result(nodeid, msg, false))
|
||||
{
|
||||
isNAck = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!msg.noAck && msg.deliveryTag > 0)
|
||||
{
|
||||
if (isNAck)
|
||||
msg.NAck();
|
||||
else
|
||||
msg.Ack();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Debug.Error("发送消息失败:" + msg.ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("分发处理任务错误时失败:" + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送结果 事件过来的
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
protected void SendResult(Message msg)
|
||||
{
|
||||
if (msg.success)
|
||||
{
|
||||
//发送成功
|
||||
if (msg.userData == null || !msg.userData.ContainsKey(successTagKey))
|
||||
{
|
||||
//没有标记 不处理
|
||||
return;
|
||||
}
|
||||
|
||||
SendOK(msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
//发送失败
|
||||
DoFail(msg, 502);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单独的消费者
|
||||
/// </summary>
|
||||
private Consumer exclusiveConsumer;
|
||||
|
||||
/// <summary>
|
||||
/// 共享的消费者
|
||||
/// </summary>
|
||||
private Consumer sharedConsumer;
|
||||
|
||||
/// <summary>
|
||||
/// 处理错误消息的消费者
|
||||
/// </summary>
|
||||
private Consumer doFailConsumer;
|
||||
|
||||
/// <summary>
|
||||
/// 过期的消息队列
|
||||
/// </summary>
|
||||
private const string exipreQueue = "expired";
|
||||
|
||||
/// <summary>
|
||||
/// 创建消费者
|
||||
/// </summary>
|
||||
public virtual void CreateConsumer()
|
||||
{
|
||||
//消费者有2 独有消息与共有消息
|
||||
Consumer consumer = new Consumer();
|
||||
consumer.noAck = false;
|
||||
consumer.noLoacl = false;
|
||||
consumer.queue = RountingManager.instance.queueNode;
|
||||
consumer.exclusive = true;
|
||||
consumer.Receive = ReciveMessage;
|
||||
exclusiveConsumer = consumer;
|
||||
rabbit.AddConsumer(consumer);
|
||||
|
||||
consumer = new Consumer();
|
||||
consumer.noAck = false;
|
||||
consumer.noLoacl = false;
|
||||
consumer.queue = RountingManager.instance.queueEveryOne;
|
||||
consumer.exclusive = false;
|
||||
consumer.Receive = ReciveMessage;
|
||||
//consumer.prefetchCount = 3;
|
||||
sharedConsumer = consumer;
|
||||
rabbit.AddConsumer(sharedConsumer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加错误消息的消费者
|
||||
/// </summary>
|
||||
public void AddFailConsumer()
|
||||
{
|
||||
return;
|
||||
Consumer consumer = new Consumer();
|
||||
consumer.noAck = false;
|
||||
consumer.noLoacl = false;
|
||||
consumer.queue = exipreQueue;
|
||||
consumer.exclusive = false;
|
||||
consumer.Receive = NotRoutingOk;
|
||||
doFailConsumer = consumer;
|
||||
rabbit.AddConsumer(doFailConsumer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移出处理失败消息的消费者
|
||||
/// </summary>
|
||||
public void RemoveFailConsumer()
|
||||
{
|
||||
if (doFailConsumer != null)
|
||||
rabbit.RemoveConsumer(doFailConsumer);
|
||||
doFailConsumer = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭模块
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
if (rabbit == null)
|
||||
return;
|
||||
rabbit.Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 等待处理的消息
|
||||
/// </summary>
|
||||
private readonly ConcurrentQueue<WaitBeMsg> _waitBeMessages = new ConcurrentQueue<WaitBeMsg>();
|
||||
|
||||
public int GteMessageCnt()
|
||||
{
|
||||
return _waitBeMessages.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拿一条消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public WaitBeMsg GetMessage()
|
||||
{
|
||||
if (_waitBeMessages.Count > 0 && _waitBeMessages.TryDequeue(out WaitBeMsg msg))
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public void AddMessage(Message msg)
|
||||
{
|
||||
WaitBeMsg tmp = WaitBeMsgPool.GetWaiteBeMsg(msg);
|
||||
_waitBeMessages.Enqueue(tmp);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
public void AddMessage(WaitBeMsg msg)
|
||||
{
|
||||
_waitBeMessages.Enqueue(msg);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建消息
|
||||
/// </summary>
|
||||
/// <param name="jsonmessage">json整包</param>
|
||||
/// <param name="failTag">失败标记</param>
|
||||
/// <param name="doFail">谁来处理失败标记</param>
|
||||
/// <param name="doFailNode">处理失败标记的节点</param>
|
||||
/// <param name="successTag">成功标记</param>
|
||||
/// <param name="userData"></param>
|
||||
/// <returns></returns>
|
||||
public static Message CreateMessage(string jsonmessage, string failTag = null, int doFail = -1,
|
||||
int doFailNode = -1, string successTag = null, IDictionary<string, object> userData = null)
|
||||
{
|
||||
Message msg = MessagePool.GetMessage();
|
||||
msg.bodystr = jsonmessage;
|
||||
IDictionary<string, object> dic = new Dictionary<string, object>();
|
||||
if (doFail != -1)
|
||||
dic[doFailKey] = doFail;
|
||||
if (failTag != null)
|
||||
dic[failTagKey] = failTag;
|
||||
if (doFailNode != -1)
|
||||
dic[doFailNodeNum] = doFailNode;
|
||||
if (successTag != null)
|
||||
dic[successTagKey] = successTag;
|
||||
|
||||
msg.userData = dic;
|
||||
msg.mandatory = true;
|
||||
msg.userData = userData;
|
||||
msg.durable = false;
|
||||
return msg;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建消息
|
||||
/// </summary>
|
||||
/// <param name="head">包头</param>
|
||||
/// <param name="otherstring">包体字符串</param>
|
||||
/// <param name="failTag">发送失败标记</param>
|
||||
/// <param name="doFail">处理失败的模块</param>
|
||||
/// <param name="doFailNode">处理失败的节点</param>
|
||||
/// <param name="successTag">处理成功的标记</param>
|
||||
/// <param name="userData"></param>
|
||||
/// <returns>消息</returns>
|
||||
public static Message CreateMessage(PackHead head, string otherstring, string failTag = null, int doFail = -1,
|
||||
int doFailNode = -1, string successTag = null, IDictionary<string, object> userData = null)
|
||||
{
|
||||
head.sendutil = GlobalMQ.instance.myUtile;
|
||||
string message = JsonPack.GetJsonByPack_head(head, otherstring);
|
||||
return CreateMessage(message, failTag, doFail, doFailNode, successTag, userData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建消息
|
||||
/// </summary>
|
||||
/// <param name="head">包头</param>
|
||||
/// <param name="data">包数据</param>
|
||||
/// <param name="failTag">发送失败的标记</param>
|
||||
/// <param name="doFail">处理失败的模块</param>
|
||||
/// <param name="doFailNode">处理失败的节点</param>
|
||||
/// <param name="successTag">处理成功的标记</param>
|
||||
/// <param name="userData"></param>
|
||||
/// <returns></returns>
|
||||
public static Message CreateMessage(PackHead head, object data = null, string failTag = null, int doFail = -1,
|
||||
int doFailNode = -1, string successTag = null, IDictionary<string, object> userData = null)
|
||||
{
|
||||
head.sendutil = GlobalMQ.instance.myUtile;
|
||||
string message = JsonPack.GetJsonByPack(head, data);
|
||||
var msg = CreateMessage(message, failTag, doFail, doFailNode, successTag, userData);
|
||||
return msg;
|
||||
}
|
||||
|
||||
#region 投递消息 message
|
||||
|
||||
/// <summary>
|
||||
/// 投递消息给一个模块 并需要知道投递结果-只能知道是否投递成功,无法知道是否到达队列
|
||||
/// </summary>
|
||||
/// <param name="target">目标</param>
|
||||
/// <param name="msg">消息</param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
/// <returns>true 表示在线并投递成功 false 表示投递失败或者目标不在线</returns>
|
||||
public bool DeliveryOne_Result(ServerNode target, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
if (msg == null)
|
||||
return false;
|
||||
|
||||
if (target == null)
|
||||
{
|
||||
Debug.Warning("target is null msg:{0}", msg);
|
||||
if (isAutoFree)
|
||||
MessagePool.PutMessage(ref msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (myUtile.Equals(target))
|
||||
{
|
||||
//发给自己的
|
||||
GlobalMQ.instance.AddMessage(msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(target.id);
|
||||
msg.routingkey = RountingManager.instance.GetNodeRouteKey(target.id, target.nodeNum);
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为空6666:" + msg.bodystr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//return CheckFiltersAndPublish(rabbit.BasicPublish_Result, msg, isAutoFree, Recv2ReturnDescription.One_Bool);//
|
||||
return rabbit.BasicPublish_Result(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投递消息给一个模块 不管结果
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
public virtual void DeliveryOne(ServerNode target, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.Warning("target is null msg:{0}", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (myUtile.Equals(target))
|
||||
{
|
||||
//发给自己的
|
||||
GlobalMQ.instance.AddMessage(msg);
|
||||
return;
|
||||
}
|
||||
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(target.id);
|
||||
msg.routingkey = RountingManager.instance.GetNodeRouteKey(target.id, target.nodeNum);
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为空5555:" + msg.bodystr);
|
||||
return;
|
||||
}
|
||||
|
||||
//CheckFiltersAndPublishNoReturn(rabbit.BasicPublish, msg, isAutoFree, Recv2ReturnDescription.One_Void);
|
||||
rabbit.BasicPublish(msg, isAutoFree);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 群发给任意模块信息
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
/// <returns></returns>
|
||||
public bool DeliveryEveryOne_Result(int moduleId, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
msg.routingkey = RountingManager.instance.GetEveryOneRouteKey(moduleId);
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为空444:" + moduleId + "," + msg.bodystr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
//return CheckFiltersAndPublish(rabbit.BasicPublish_Result, msg, isAutoFree, Recv2ReturnDescription.EveryOne_Bool);
|
||||
return rabbit.BasicPublish_Result(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 群发给任意模块信息
|
||||
/// </summary>
|
||||
/// <param name="moduleId">目标模块id</param>
|
||||
/// <param name="msg">消息内容</param>
|
||||
/// <returns>没有绑定该模块则为false 绑定则为true</returns>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
public void DeliveryEveryOne(int moduleId, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
msg.routingkey = RountingManager.instance.GetEveryOneRouteKey(moduleId);
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为空333:" + msg.bodystr);
|
||||
return;
|
||||
}
|
||||
|
||||
//CheckFiltersAndPublishNoReturn(rabbit.BasicPublish, msg, isAutoFree, Recv2ReturnDescription.EveryOne_Void);
|
||||
rabbit.BasicPublish(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投递这个模块的所有节点
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
public bool DeliveryAll_Result(int moduleId, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
msg.routingkey = RountingManager.instance.routeallkey;
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机与路由键为空!111" + msg.bodystr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckFiltersAndPublish(rabbit.BasicPublish_Result, msg, isAutoFree,
|
||||
Recv2ReturnDescription.All_Bool); //rabbit.BasicPublish_Result(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投递给这类所有模块
|
||||
/// </summary>
|
||||
/// <param name="moduleId">目标类模块id</param>
|
||||
/// <param name="msg">消息内容</param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
public void DeliveryAll(int moduleId, Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
msg.routingkey = RountingManager.instance.routeallkey;
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机与路由键为空!222:" + msg.bodystr);
|
||||
return;
|
||||
}
|
||||
|
||||
//CheckFiltersAndPublishNoReturn(rabbit.BasicPublish, msg, isAutoFree, Recv2ReturnDescription.All_Void);
|
||||
rabbit.BasicPublish(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投递给所有模块
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化处理</param>
|
||||
public bool DeliverAll_Result(Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.AllServerRouteName;
|
||||
msg.routingkey = RountingManager.instance.routeallkey;
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
// Debug.Error("消息的交换机或路由键为空!7777" + msg.bodystr);
|
||||
return false;
|
||||
}
|
||||
|
||||
return CheckFiltersAndPublish(rabbit.BasicPublish_Result, msg, isAutoFree,
|
||||
Recv2ReturnDescription.All_Bool); //rabbit.BasicPublish_Result(msg, isAutoFree);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 投递给所有模块
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <param name="durable">持久化</param>
|
||||
public void DeliveryAll(Message msg, bool isAutoFree, bool durable = false)
|
||||
{
|
||||
msg.exchange = RountingManager.AllServerRouteName;
|
||||
msg.routingkey = RountingManager.instance.routeallkey;
|
||||
msg.durable = durable;
|
||||
|
||||
if (string.IsNullOrEmpty(msg.exchange) || string.IsNullOrEmpty(msg.routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为空!8888:" + msg.bodystr);
|
||||
return;
|
||||
}
|
||||
|
||||
//CheckFiltersAndPublishNoReturn(rabbit.BasicPublish, msg, true, Recv2ReturnDescription.All_Void);
|
||||
rabbit.BasicPublish(msg, isAutoFree);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// RPC Call 方法
|
||||
/// </summary>
|
||||
/// <param name="target">目标</param>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="waitTime">等待多久</param>
|
||||
/// <returns></returns>
|
||||
public string Call(ServerNode target, string message, int waitTime = 3000)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.Warning("target is null msg:{0}", message);
|
||||
return null;
|
||||
}
|
||||
|
||||
string exchange = RountingManager.instance.GetClusterRoute(target.id);
|
||||
string routingkey = RountingManager.instance.GetNodeRouteKey(target.id, target.nodeNum);
|
||||
|
||||
if (string.IsNullOrEmpty(exchange) || string.IsNullOrEmpty(routingkey))
|
||||
{
|
||||
Debug.Error("消息的交换机或路由键为 call 5555:" + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
return CheckFiltersAndCall(() => rpcClient.Call(exchange, routingkey, message, waitTime), message,
|
||||
Recv2ReturnDescription.Call_One_String);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC Call 任意一个模块
|
||||
/// </summary>
|
||||
/// <param name="moduleId">目标id</param>
|
||||
/// <param name="message">消息</param>
|
||||
/// <param name="waitTime">等待多久</param>
|
||||
/// <returns></returns>
|
||||
public string Call_EveryOne(int moduleId, string message, int waitTime = 3000)
|
||||
{
|
||||
string exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
string routingkey = RountingManager.instance.GetEveryOneRouteKey(moduleId);
|
||||
|
||||
if (string.IsNullOrEmpty(exchange) || string.IsNullOrEmpty(routingkey))
|
||||
{
|
||||
Debug.Error("消息交换或路由键为 call 6666:" + moduleId + "," + message);
|
||||
return null;
|
||||
}
|
||||
|
||||
var ret = CheckFiltersAndCall(() => rpcClient.Call(exchange, routingkey, message, waitTime), message,
|
||||
Recv2ReturnDescription.Call_EveryOne_String);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public string Call(ServerNode target, PackHead head, object data = null, int waitTime = 3000)
|
||||
{
|
||||
string message = JsonPack.GetJsonByPack(head, data);
|
||||
return Call(target, message, waitTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rpc call
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="jsonmessage"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public string Call(ServerNode target, PackHead head, string jsonmessage, int waitTime = 3000)
|
||||
{
|
||||
string message = JsonPack.GetJsonByPack_head(head, jsonmessage);
|
||||
return Call(target, message, waitTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// call 方法
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public string Call_EveryOne(int moduleId, PackHead head, object data = null, int waitTime = 3000)
|
||||
{
|
||||
string message = JsonPack.GetJsonByPack(head, data);
|
||||
return Call_EveryOne(moduleId, message, waitTime);
|
||||
}
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="data"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public System.Threading.Tasks.Task<string> AsyncCall_EveryOne(int moduleId, ServerHead head, object data = null, int waitTime = 3000) {
|
||||
string message = JsonPack.GetJsonByPack(head, data);
|
||||
return AsyncCall_EveryOne(moduleId, message, waitTime);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public System.Threading.Tasks.Task<string> AsyncCall_EveryOne(int moduleId, string message, int waitTime = 3000) {
|
||||
string exchange = RountingManager.instance.GetClusterRoute(moduleId);
|
||||
string routingkey = RountingManager.instance.GetEveryOneRouteKey(moduleId);
|
||||
|
||||
if(string.IsNullOrEmpty(exchange) || string.IsNullOrEmpty(routingkey)) {
|
||||
Debug.Error("消息交换或路由键为 call 6666:" + message);
|
||||
return null;
|
||||
}
|
||||
var ret = rpcClient.AsyncCall(exchange, routingkey, message, waitTime);
|
||||
return ret;
|
||||
}
|
||||
*/
|
||||
|
||||
/// <summary>
|
||||
/// call 方法
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="head"></param>
|
||||
/// <param name="jsonmessage"></param>
|
||||
/// <param name="waitTime"></param>
|
||||
/// <returns></returns>
|
||||
public string Call_EveryOne_str(int moduleId, PackHead head, string jsonmessage = null, int waitTime = 3000)
|
||||
{
|
||||
string message = JsonPack.GetJsonByPack_head(head, jsonmessage);
|
||||
return Call_EveryOne(moduleId, message, waitTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC回复
|
||||
/// </summary>
|
||||
/// <param name="ibp"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="userData"></param>
|
||||
public void CallBack(IBasicProperties ibp, object message, IDictionary<string, object> userData)
|
||||
{
|
||||
Message msg = MessagePool.GetMessage();
|
||||
msg.exchange = string.Empty;
|
||||
msg.routingkey = ibp.ReplyTo;
|
||||
msg.propertis = rabbit.GetBasicProperties();
|
||||
msg.propertis.CorrelationId = ibp.CorrelationId;
|
||||
msg.bodystr = JsonPack.GetJson(message);
|
||||
msg.userData = userData;
|
||||
Debug.Log("RPC回复:" + msg.propertis.CorrelationId);
|
||||
|
||||
CheckFiltersCallbackAndPublishNoReturn(rabbit.BasicPublish, msg, true, Recv2ReturnDescription.CallBack);
|
||||
//rabbit.BasicPublish(msg, true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// AddFilter
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
public static void AddFilter(IMQFilter filter)
|
||||
{
|
||||
Filters.Add(filter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="filter"></param>
|
||||
public static void RemoveFilter(IMQFilter filter)
|
||||
{
|
||||
if (Filters.Contains(filter))
|
||||
{
|
||||
Filters.Remove(filter);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static ICollection<IMQFilter> Filters { get; } =
|
||||
new System.Collections.ObjectModel.Collection<IMQFilter>();
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="defaultPublisher"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
protected static void CheckFiltersAndPublishNoReturn(Action<Message, bool> defaultPublisher, Message msg,
|
||||
bool isAutoFree, Recv2ReturnDescription msgDesc)
|
||||
{
|
||||
var filer = Filters.FirstOrDefault(p => p.Filter(msg, msgDesc));
|
||||
if (filer != null)
|
||||
{
|
||||
filer.HandleMessage(msg, msgDesc);
|
||||
MessagePool.PutMessage(ref msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultPublisher(msg, isAutoFree);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="defaultPublisher"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
protected static void CheckFiltersCallbackAndPublishNoReturn(Action<Message, bool> defaultPublisher,
|
||||
Message msg, bool isAutoFree, Recv2ReturnDescription msgDesc)
|
||||
{
|
||||
var filer = Filters.FirstOrDefault(p => p.FilterCallback(msg));
|
||||
if (filer != null)
|
||||
{
|
||||
filer.HandleCallbackMessage(msg);
|
||||
MessagePool.PutMessage(ref msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
defaultPublisher(msg, isAutoFree);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="defaultPublisher"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
protected static T CheckFiltersAndPublish<T>(Func<Message, bool, T> defaultPublisher, Message msg,
|
||||
bool isAutoFree, Recv2ReturnDescription msgDesc)
|
||||
{
|
||||
var filer = Filters.FirstOrDefault(p => p.Filter(msg, msgDesc));
|
||||
if (filer != null)
|
||||
{
|
||||
var ret = filer.HandleMessage(msg, msgDesc);
|
||||
if (ret is T value)
|
||||
{
|
||||
MessagePool.PutMessage(ref msg);
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
$"消息过滤器: {filer.Name} 返回值类型无效, 期待类型:{typeof(T)}, 当前类型: {ret?.GetType()}, returnResult: {msgDesc}");
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultPublisher(msg, isAutoFree);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
/// <param name="defaultPublisher"></param>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
protected static T CheckFiltersAndCall<T>(Func<T> defaultPublisher, string msg, Recv2ReturnDescription msgDesc)
|
||||
{
|
||||
var filer = Filters.FirstOrDefault(p => p.CallFilter(msg, msgDesc));
|
||||
if (filer != null)
|
||||
{
|
||||
var ret = filer.HandleCallMessage(msg, msgDesc);
|
||||
if (ret is T value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
$"消息过滤器: {filer.Name} 返回值类型无效, 期待类型:{typeof(T)}, 当前类型: {ret?.GetType()}, returnResult: {msgDesc}");
|
||||
}
|
||||
else
|
||||
{
|
||||
return defaultPublisher();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 外发到rabbit消息的过滤器
|
||||
/// </summary>
|
||||
public interface IMQFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// 过滤器名称
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// 检查此消息是否符合过滤条件
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
bool Filter(Message message, Recv2ReturnDescription msgDesc);
|
||||
|
||||
/// <summary>
|
||||
/// FilterCallback
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
bool FilterCallback(Message message);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
void HandleCallbackMessage(Message message);
|
||||
|
||||
/// <summary>
|
||||
/// 处理此消息
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
object HandleMessage(Message message, Recv2ReturnDescription msgDesc);
|
||||
|
||||
/// <summary>
|
||||
/// 检查RPC Call 消息是否符合过滤条件
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
bool CallFilter(string msg, Recv2ReturnDescription msgDesc);
|
||||
|
||||
/// <summary>
|
||||
/// 处理 RPC Call 消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="msgDesc"></param>
|
||||
/// <returns></returns>
|
||||
object HandleCallMessage(string msg, Recv2ReturnDescription msgDesc);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ReturnResult
|
||||
/// </summary>
|
||||
public enum Recv2ReturnDescription : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// EveryOne, 无返回
|
||||
/// </summary>
|
||||
EveryOne_Void = 1,
|
||||
|
||||
/// <summary>
|
||||
/// EveryOne, 返回 bool
|
||||
/// </summary>
|
||||
EveryOne_Bool = 2,
|
||||
|
||||
/// <summary>
|
||||
/// EveryOne, 返回 string
|
||||
/// </summary>
|
||||
EveryOne_String = 3,
|
||||
|
||||
/// <summary>
|
||||
/// CallBack
|
||||
/// </summary>
|
||||
CallBack = 10,
|
||||
|
||||
/// <summary>
|
||||
/// All, 无返回
|
||||
/// </summary>
|
||||
All_Void = 20,
|
||||
|
||||
/// <summary>
|
||||
/// All, 返回 bool
|
||||
/// </summary>
|
||||
All_Bool = 21,
|
||||
|
||||
/// <summary>
|
||||
/// One 无返回
|
||||
/// </summary>
|
||||
One_Void = 30,
|
||||
|
||||
/// <summary>
|
||||
/// One, 返回 bool
|
||||
/// </summary>
|
||||
One_Bool = 31,
|
||||
|
||||
/// <summary>
|
||||
/// Call EveryOne, 返回 string
|
||||
/// </summary>
|
||||
Call_EveryOne_String = 40,
|
||||
|
||||
/// <summary>
|
||||
/// Call One, 返回 string
|
||||
/// </summary>
|
||||
Call_One_String = 41,
|
||||
}
|
||||
}
|
||||
44
GlobalSever/MQ/IGlobalMQ.cs
Normal file
44
GlobalSever/MQ/IGlobalMQ.cs
Normal file
@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using MrWu.RabbitMQ;
|
||||
|
||||
namespace Server.MQ {
|
||||
/// <summary>
|
||||
/// 消息处理
|
||||
/// </summary>
|
||||
public interface IGlobalMQ {
|
||||
|
||||
/// <summary>
|
||||
/// 发送成功
|
||||
/// </summary>
|
||||
/// <param name="msg">成功的消息</param>
|
||||
bool SendOK(Message msg);
|
||||
|
||||
/// <summary>
|
||||
/// 发送失败
|
||||
/// </summary>
|
||||
/// <param name="msg">发送失败的消息</param>
|
||||
void SendFail(Message msg);
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息
|
||||
/// </summary>
|
||||
/// <param name="msg">消息</param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
void SendMessage(Message msg,bool isAutoFree);
|
||||
|
||||
/// <summary>
|
||||
/// 发送消息并返回发送结果
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
/// <param name="isAutoFree">是否自动释放</param>
|
||||
/// <returns></returns>
|
||||
bool SendMessage_Result(Message msg,bool isAutoFree);
|
||||
|
||||
/// <summary>
|
||||
/// 接收消息
|
||||
/// </summary>
|
||||
/// <param name="msg"></param>
|
||||
void ReciveMessage(Message msg);
|
||||
|
||||
}
|
||||
}
|
||||
249
GlobalSever/MQ/Rountingkey.cs
Normal file
249
GlobalSever/MQ/Rountingkey.cs
Normal file
@ -0,0 +1,249 @@
|
||||
/*
|
||||
* 作者:吴隆健
|
||||
* 日期: 2019-04-16
|
||||
* 时间: 14:42
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Server.Data.Module;
|
||||
using GameData;
|
||||
using Server.DB.Redis;
|
||||
using System.Collections.Concurrent;
|
||||
|
||||
namespace Server {
|
||||
/// <summary>
|
||||
/// 路由管理
|
||||
/// </summary>
|
||||
public class RountingManager : ServerNode {
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static RountingManager instance { get; } = new RountingManager();
|
||||
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public string moduleName {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 所有模块的名称_用来发送用的
|
||||
/// </summary>
|
||||
public readonly ConcurrentDictionary<int, string> moduleNames = new ConcurrentDictionary<int, string>();
|
||||
|
||||
//------------------------------路由名称---------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 系统群发路由
|
||||
/// </summary>
|
||||
public const string AllServerRouteName = "ServerAll";
|
||||
|
||||
private string m_clubsterRouteName;
|
||||
/// <summary>
|
||||
/// 集群主路由-发给本模块都需要经过此路由器
|
||||
/// </summary>
|
||||
public string clubsterRouteName {
|
||||
get {
|
||||
if (m_clubsterRouteName == null)
|
||||
m_clubsterRouteName = moduleName + "." + id;
|
||||
return m_clubsterRouteName;
|
||||
}
|
||||
}
|
||||
|
||||
private string m_clusterAllRouteName;
|
||||
/// <summary>
|
||||
/// 集群群发路由-集群路由转发而来
|
||||
/// </summary>
|
||||
public string clusterAllRouteName {
|
||||
get {
|
||||
if (m_clusterAllRouteName == null)
|
||||
m_clusterAllRouteName = clubsterRouteName + ".all";
|
||||
return m_clusterAllRouteName;
|
||||
}
|
||||
}
|
||||
|
||||
private string m_clusterNodeOne;
|
||||
/// <summary>
|
||||
/// 集群单点路由
|
||||
/// </summary>
|
||||
public string clusterNodeOne {
|
||||
get {
|
||||
if (m_clusterNodeOne == null)
|
||||
m_clusterNodeOne = clubsterRouteName + ".one";
|
||||
return m_clusterNodeOne;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------队列名称----------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 群发所有的路由键
|
||||
/// </summary>
|
||||
public string routeallkey = "all";
|
||||
|
||||
private string m_routeEveryOneKey;
|
||||
/// <summary>
|
||||
/// 发送给集群中的任意一个-这个通常谁处理都可以-升级时候有大用处-负载均衡
|
||||
/// </summary>
|
||||
public string routeEveryOneKey {
|
||||
get {
|
||||
if (m_routeEveryOneKey == null)
|
||||
m_routeEveryOneKey = clubsterRouteName + ".everyOne";
|
||||
return m_routeEveryOneKey;
|
||||
}
|
||||
}
|
||||
|
||||
private string m_nodeRouteKey;
|
||||
/// <summary>
|
||||
/// 路由到本模块队列的路由键
|
||||
/// </summary>
|
||||
public string nodeRouteKey {
|
||||
get {
|
||||
if (m_nodeRouteKey == null)
|
||||
m_nodeRouteKey = clubsterRouteName + ".one." + nodeNum;
|
||||
return m_nodeRouteKey;
|
||||
}
|
||||
}
|
||||
|
||||
private string m_nodeRouteMatch;
|
||||
/// <summary>
|
||||
/// 路由匹配键
|
||||
/// </summary>
|
||||
public string nodeRouteMatch {
|
||||
get {
|
||||
if (m_nodeRouteMatch == null) {
|
||||
m_nodeRouteMatch = clubsterRouteName + ".one.*";
|
||||
}
|
||||
return m_nodeRouteMatch;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------队列名--------------------------
|
||||
|
||||
private string m_queueEveryOne;
|
||||
/// <summary>
|
||||
/// 任意队列
|
||||
/// </summary>
|
||||
public string queueEveryOne {
|
||||
get {
|
||||
if (m_queueEveryOne == null) {
|
||||
m_queueEveryOne = clubsterRouteName + ".everyOne";
|
||||
}
|
||||
return m_queueEveryOne;
|
||||
}
|
||||
}
|
||||
|
||||
private string m_queueNode;
|
||||
/// <summary>
|
||||
/// 本节点的队列名
|
||||
/// </summary>
|
||||
public string queueNode {
|
||||
get {
|
||||
if (m_queueNode == null)
|
||||
m_queueNode = clubsterRouteName + ".node." + nodeNum;
|
||||
return m_queueNode;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------其他模块路由-----------------------
|
||||
|
||||
private readonly ConcurrentDictionary<int, string> otherClusterRouteKey = new ConcurrentDictionary<int, string>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取某集群路由
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <returns></returns>
|
||||
public string GetClusterRoute(int moduleId) {
|
||||
string key = null;
|
||||
|
||||
if (!otherClusterRouteKey.TryGetValue(moduleId, out key)) {
|
||||
key = GetModuleName(moduleId);
|
||||
if (!string.IsNullOrEmpty(key)) {
|
||||
key = key + "." + moduleId;
|
||||
otherClusterRouteKey.TryAdd(moduleId, key);
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
//----------------------------=其他模块的路由键-------------------
|
||||
|
||||
private readonly ConcurrentDictionary<int, string> otherEveryOneRouteKey = new ConcurrentDictionary<int, string>();
|
||||
/// <summary>
|
||||
/// 任意节点路由键
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <returns></returns>
|
||||
public string GetEveryOneRouteKey(int moduleId) {
|
||||
string key = null;
|
||||
if (!otherEveryOneRouteKey.TryGetValue(moduleId, out key)) {
|
||||
key = GetModuleName(moduleId);
|
||||
if (!string.IsNullOrEmpty(key)) {
|
||||
key = key + "." + moduleId + ".everyOne";
|
||||
otherEveryOneRouteKey.TryAdd(moduleId, key);
|
||||
}
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
private readonly ConcurrentDictionary<int, string> otherNodeRouteKey = new ConcurrentDictionary<int, string>();
|
||||
/// <summary>
|
||||
/// 获取某个节点的路由键
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="nodeNum"></param>
|
||||
/// <returns></returns>
|
||||
public string GetNodeRouteKey(int moduleId, int nodeNum) {
|
||||
string key = null;
|
||||
int pwd = moduleId * 1000 + nodeNum;
|
||||
|
||||
if (!otherNodeRouteKey.TryGetValue(pwd, out key)) {
|
||||
key = GetModuleName(moduleId);
|
||||
if (!string.IsNullOrEmpty(key)) {
|
||||
key = key + "." + moduleId + ".one." + nodeNum;
|
||||
otherNodeRouteKey.TryAdd(pwd, key);
|
||||
}
|
||||
}
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 启动
|
||||
/// </summary>
|
||||
public void Start(ModuleType type, int nodeNum) {
|
||||
this.id = (int)type;
|
||||
this.nodeNum = nodeNum;
|
||||
this.moduleName = Enum.GetName(type.GetType(), type);
|
||||
AddModule(id, moduleName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 注册添加模块
|
||||
/// </summary>
|
||||
public void AddModule(int moduleId, string moduleName) {
|
||||
if (!moduleNames.ContainsKey(moduleId)) {
|
||||
moduleNames.TryAdd(moduleId, moduleName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取模块名称
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <returns></returns>
|
||||
public string GetModuleName(int moduleId) {
|
||||
string result;
|
||||
if (!moduleNames.TryGetValue(moduleId, out result)) {
|
||||
result = redisManager.db.HashGet(RedisDictionary.moduleNames, moduleId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
571
GlobalSever/MQ/ServerHeart.cs
Normal file
571
GlobalSever/MQ/ServerHeart.cs
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* 作者:吴隆健
|
||||
* 日期: 2019-04-15
|
||||
* 时间: 15:27
|
||||
*
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using Server.DB.Redis;
|
||||
using Server.Data.Module;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using MrWu.Debug;
|
||||
using System.Threading.Tasks;
|
||||
using GameData;
|
||||
using Server.Core;
|
||||
using Server.MQ;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
//发包就四种情况
|
||||
|
||||
|
||||
/*
|
||||
* 1.发所有
|
||||
* 2.发某类模块的所有
|
||||
* 3.发给指定的
|
||||
* 4.发给某类模块的任意一个
|
||||
* */
|
||||
|
||||
//拦截多开与检查断线
|
||||
//提供的服务就是判断在不在线,
|
||||
/// <summary>
|
||||
/// 服务器生命检查
|
||||
/// </summary>
|
||||
public class ServerHeart : ServerNode
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static ServerHeart instanece {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public bool IsSendHeart = false;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
protected ServerHeart() { }
|
||||
|
||||
static ServerHeart() {
|
||||
instanece = new ServerHeart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模块类型
|
||||
/// </summary>
|
||||
public ModuleType myType {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 模块名称
|
||||
/// </summary>
|
||||
public string moduleName {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 未收到心跳的最长时间,超过这个事件认为是掉线
|
||||
/// </summary>
|
||||
private const int MaxNoGetHeart = 40;
|
||||
|
||||
/// <summary>
|
||||
/// 1分钟不更新认为自己死亡
|
||||
/// </summary>
|
||||
private readonly TimeSpan heartTime = new TimeSpan(0, 0, MaxNoGetHeart);
|
||||
|
||||
/// <summary>
|
||||
/// 1分钟不更新认为死亡 单位秒
|
||||
/// </summary>
|
||||
private const int dieTime = MaxNoGetHeart * 1000;
|
||||
|
||||
/// <summary>
|
||||
/// 所有的服务器->这个数据
|
||||
/// </summary>
|
||||
private readonly ConcurrentDictionary<int, ClusterInfo> Servers = new ConcurrentDictionary<int, ClusterInfo>();
|
||||
|
||||
private string m_nodeHeartKey;
|
||||
|
||||
/// <summary>
|
||||
/// 节点信息 key
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string nodeHeartKey {
|
||||
get
|
||||
{
|
||||
if (m_nodeHeartKey == null)
|
||||
m_nodeHeartKey = GetNodeHeartKey(moduleName, nodeNum); // "Game:LockModule:Module." + moduleName + "." + nodeNum;
|
||||
return m_nodeHeartKey;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetNodeHeartKey(string moduleName,int nodeNum)
|
||||
{
|
||||
return $"Game:LockModule:Module.{moduleName}.{nodeNum}";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定时器 _ 线程定时器
|
||||
/// </summary>
|
||||
private Timer timer;
|
||||
|
||||
DistributedLock disLock = new DistributedLock(10);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="nodeNum"></param>
|
||||
/// <returns></returns>
|
||||
//启动 -> 因为操作同一个库,所以必须分布式锁 -> 从redis中获取到自己这个服务器的编号
|
||||
public bool Start(ModuleType type, int nodeNum) {
|
||||
this.myType = type;
|
||||
this.moduleName = Enum.GetName(type.GetType(), type);
|
||||
this.id = (int)type;
|
||||
this.nodeNum = nodeNum;
|
||||
//检查redis中的数据
|
||||
|
||||
bool start = disLock.LockRun(nodeHeartKey,() => {
|
||||
if (redisManager.db.KeyExists(nodeHeartKey))
|
||||
return false;
|
||||
return Heart();
|
||||
});
|
||||
|
||||
AddModule(id,moduleName, nodeNum);
|
||||
|
||||
if (start) {
|
||||
//10秒一次
|
||||
timer = new Timer(OnTime, null, 0, 10000);
|
||||
}
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 正常关闭模块
|
||||
/// </summary>
|
||||
public void Close() {
|
||||
timer.Dispose();
|
||||
if (heartTimer != null)
|
||||
heartTimer.Dispose();
|
||||
disLock.LockRun(nodeHeartKey, () => {
|
||||
if (redisManager.db.KeyExists(nodeHeartKey))
|
||||
redisManager.db.KeyDelete(nodeHeartKey);
|
||||
});
|
||||
}
|
||||
|
||||
private List<NodeInfo> tmpdieNode = new List<NodeInfo>();
|
||||
|
||||
/// <summary>
|
||||
/// 定时器
|
||||
/// </summary>
|
||||
private void OnTime(Object obj) {
|
||||
//心跳
|
||||
HeartAsync();
|
||||
|
||||
tmpdieNode.Clear();
|
||||
//每10秒检测一次所有服务器是否掉线
|
||||
try {
|
||||
foreach (var ser in Servers.Values) {
|
||||
foreach (var node in ser.nodes.Values) {
|
||||
if (node.type == id && node.nodeNum == nodeNum) continue;
|
||||
if (node.ExpireTime - TimeInfo.Instance.FrameTime < 15) //距离过期时间剩下15秒内 才去检查
|
||||
{
|
||||
if (!tmpdieNode.Contains(node)) {
|
||||
tmpdieNode.Add(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("D12E5112-817D-40C0-A8FB-CED9AC969945:" + e.ToString());
|
||||
}
|
||||
|
||||
_ = CheckDie();
|
||||
}
|
||||
|
||||
private async Task CheckDie()
|
||||
{
|
||||
if (tmpdieNode.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
List<NodeInfo> checks = new List<NodeInfo>();
|
||||
List<Task<TimeSpan?>> timeSpans = new List<Task<TimeSpan?>>();
|
||||
IBatch batch = redisManager.db.CreateBatch();
|
||||
for (int i = 0; i < tmpdieNode.Count; i++)
|
||||
{
|
||||
checks.Add(tmpdieNode[i]);
|
||||
timeSpans.Add(batch.KeyTimeToLiveAsync(GetNodeHeartKey(tmpdieNode[i].ModuleName, tmpdieNode[i].nodeNum)));
|
||||
}
|
||||
batch.Execute();
|
||||
await Task.WhenAll(timeSpans);
|
||||
|
||||
for (int i = 0; i < checks.Count; i++)
|
||||
{
|
||||
if (timeSpans[i].Result == null)
|
||||
{
|
||||
Debug.ImportantLog($"模块掉线:{checks[i].ModuleName}-{checks[i].nodeNum}");
|
||||
checks[i].isDie = true;
|
||||
RemoveDie(checks[i].type, checks[i].nodeNum);
|
||||
GlobalDispatcher.Instance.DispatchNextFrame(GlobalMsgId.ModuleNodeCrash,checks[i].ModuleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
checks[i].ExpireTime = TimeInfo.Instance.FrameTime + (long)timeSpans[i].Result.Value.TotalMilliseconds;
|
||||
//Debug.Info($"过期时间:{checks[i].ModuleName} {checks[i].nodeNum} {checks[i].ExpireTime}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加模块
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="nodeNum"></param>
|
||||
public void AddModule(int moduleId,string moduleName,int nodeNum)
|
||||
{
|
||||
try
|
||||
{
|
||||
ClusterInfo ci = Servers.GetOrAdd(moduleId, new ClusterInfo()
|
||||
{
|
||||
type = moduleId,
|
||||
ModuleName = moduleName
|
||||
});
|
||||
|
||||
NodeInfo node = ci.nodes.GetOrAdd(nodeNum, new NodeInfo()
|
||||
{
|
||||
type = moduleId,
|
||||
ModuleName = moduleName,
|
||||
nodeNum = nodeNum,
|
||||
isDie = false
|
||||
});
|
||||
|
||||
node.ExpireTime = TimeInfo.Instance.FrameTime + dieTime;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("1AD0CEC8-1ACB-4CEC-AB11-EB86C8A63C75:" + e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// 处理心跳
|
||||
// /// </summary>
|
||||
// /// <param name="moduleId"></param>
|
||||
// /// <param name="nodeNum"></param>
|
||||
// public void DoHeart(int moduleId, int nodeNum) {
|
||||
// //心跳
|
||||
// try
|
||||
// {
|
||||
// ClusterInfo ci = Servers.GetOrAdd(moduleId, new ClusterInfo()
|
||||
// {
|
||||
// type = moduleId
|
||||
// });
|
||||
//
|
||||
// NodeInfo node = ci.nodes.GetOrAdd(nodeNum, new NodeInfo()
|
||||
// {
|
||||
// type = moduleId,
|
||||
// nodeNum = nodeNum
|
||||
// });
|
||||
//
|
||||
// node.LastActivityTime = TimeInfo.Instance.FrameTime;
|
||||
// } catch (Exception e) {
|
||||
// Debug.Error("1AD0CEC8-1ACB-4CEC-AB11-EB86C8A63C75:" + e.ToString());
|
||||
// }
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// 来心跳
|
||||
// /// </summary>
|
||||
// /// <param name="moduleId"></param>
|
||||
// /// <param name="nodeNum"></param>
|
||||
// public Task DoHeartAsync(int moduleId, int nodeNum) {
|
||||
// return Task.Run(
|
||||
// () => DoHeart(moduleId, nodeNum)
|
||||
// );
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// 某个模块是否死亡
|
||||
/// </summary>
|
||||
public Task<bool> IsDieAsync(int moduleId, int nodeNum) {
|
||||
return Task.Run(() => IsDie(moduleId, nodeNum));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查节点死否死亡
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="nodeNum"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsDie(int moduleId, int nodeNum) {
|
||||
bool result = true;
|
||||
|
||||
try {
|
||||
if (Servers.TryGetValue(moduleId, out ClusterInfo ci))
|
||||
{
|
||||
if (ci.nodes.TryGetValue(nodeNum, out NodeInfo node))
|
||||
{
|
||||
result = node.isDie;
|
||||
if (result)
|
||||
RemoveDie(moduleId, nodeNum);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("FC703541-D8AB-4641-9618-9CB0F090FFE4:" + e.ToString());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查该模块是否没有一个在线
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <returns></returns>
|
||||
public bool IsDie(int moduleId) {
|
||||
bool result = true;
|
||||
try {
|
||||
if (Servers.TryGetValue(moduleId, out ClusterInfo ci)) {
|
||||
foreach (var node in ci.nodes.Values) {
|
||||
if (!node.isDie) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("78A9B0FC-9EFF-4E53-B921-F5EF328BCF5F:" + e.ToString());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 输出日志
|
||||
/// </summary>
|
||||
public string Log() {
|
||||
string str = string.Empty;
|
||||
str += id + "," + nodeNum + ":";
|
||||
|
||||
str += Environment.NewLine;
|
||||
|
||||
try {
|
||||
foreach (var ser in Servers.Values) {
|
||||
foreach (NodeInfo node in ser.nodes.Values) {
|
||||
str += "在线的模块:" + node.type + "," + node.nodeNum +"," + Environment.NewLine;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("E4BEB6EB-465A-428B-9C5D-85264A108429:" + e.ToString());
|
||||
}
|
||||
|
||||
//str += Environment.NewLine;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除死亡的模块
|
||||
/// </summary>
|
||||
/// <param name="moduleId"></param>
|
||||
/// <param name="nodeNum"></param>
|
||||
public Task RemoveDie(int moduleId, int nodeNum, bool force = false) {
|
||||
|
||||
//移除死掉的节点
|
||||
return Task.Run(() => {
|
||||
bool r = false;
|
||||
try {
|
||||
ClusterInfo ci = null;
|
||||
if (Servers.TryGetValue(moduleId, out ci)) {
|
||||
NodeInfo node = null;
|
||||
if (ci.nodes.TryGetValue(nodeNum, out node)) {
|
||||
if (node.isDie && (moduleId != this.id || nodeNum != this.nodeNum)) {
|
||||
r = ci.nodes.TryRemove(nodeNum,out _);
|
||||
} else if (force) {
|
||||
r = ci.nodes.TryRemove(nodeNum,out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("3D910EC1-3682-44B2-A767-4FC8517BFD2D:" + e.ToString());
|
||||
}
|
||||
|
||||
if (r) {
|
||||
GlobalDispatcher.Instance.DispatchNextFrame(GlobalMsgId.ModuleNodeDie,new ServerNode(moduleId,nodeNum));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的在线的节点
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ServerNode> GetAllOnline() {
|
||||
List<ServerNode> nodes = new List<ServerNode>();
|
||||
try
|
||||
{
|
||||
foreach (var ser in Servers.Values)
|
||||
{
|
||||
foreach (var node in ser.nodes.Values)
|
||||
{
|
||||
if (!node.isDie)
|
||||
nodes.Add(new ServerNode(node.type, node.nodeNum));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.Error("F95EF643-7315-48A6-8D07-1606E16102D3:" + e.ToString());
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有的在线节点
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<ServerNode> GetAllOnline(int moduleId) {
|
||||
List<ServerNode> nodes = new List<ServerNode>();
|
||||
try {
|
||||
ClusterInfo ci = null;
|
||||
if (Servers.TryGetValue(moduleId, out ci)) {
|
||||
foreach (var node in ci.nodes.Values) {
|
||||
if (!node.isDie)
|
||||
nodes.Add(new ServerNode(node.type, node.nodeNum));
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Debug.Error("E1C6A85D-8F0C-47A9-8103-5AC3D7ACDF0B:" + e.ToString());
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 心跳
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private Task<bool> HeartAsync() {
|
||||
return redisManager.db.StringSetAsync(nodeHeartKey, "online", heartTime);
|
||||
}
|
||||
|
||||
private bool Heart()
|
||||
{
|
||||
return redisManager.db.StringSet(nodeHeartKey, "online", heartTime);
|
||||
}
|
||||
|
||||
#region 心跳包发送处理
|
||||
/// <summary>
|
||||
/// 发送心跳包定时器
|
||||
/// </summary>
|
||||
private Timer heartTimer;
|
||||
|
||||
/// <summary>
|
||||
/// 12秒钟发送一次心跳包
|
||||
/// </summary>
|
||||
const int constheartTime = 12000;
|
||||
|
||||
/// <summary>
|
||||
/// 心跳包
|
||||
/// </summary>
|
||||
private string heartPack;
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 开始发送
|
||||
/// </summary>
|
||||
/// <param name="heartPack"></param>
|
||||
public void BeginHeart(string heartPack) {
|
||||
this.heartPack = heartPack;
|
||||
heartTimer = new Timer(SendHeart, null, 0, constheartTime);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更改心跳包
|
||||
/// </summary>
|
||||
public void ChangeHeart(string heartPack) {
|
||||
this.heartPack = heartPack;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送心跳包
|
||||
/// </summary>
|
||||
private void SendHeart(object state) {
|
||||
if (!IsSendHeart)
|
||||
{
|
||||
return;
|
||||
}
|
||||
GlobalMQ.instance.DeliveryAll(GlobalMQ.CreateMessage(heartPack), true);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 集群信息
|
||||
/// </summary>
|
||||
private class ClusterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 模块id
|
||||
/// </summary>
|
||||
public int type;
|
||||
|
||||
/// <summary>
|
||||
/// 模块名称
|
||||
/// </summary>
|
||||
public string ModuleName;
|
||||
|
||||
/// <summary>
|
||||
/// 节点id
|
||||
/// </summary>
|
||||
public ConcurrentDictionary<int, NodeInfo> nodes = new ConcurrentDictionary<int, NodeInfo>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 节点信息
|
||||
/// </summary>
|
||||
private class NodeInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 类型
|
||||
/// </summary>
|
||||
public int type;
|
||||
|
||||
/// <summary>
|
||||
/// 模块名称
|
||||
/// </summary>
|
||||
public string ModuleName;
|
||||
|
||||
/// <summary>
|
||||
/// 节点
|
||||
/// </summary>
|
||||
public int nodeNum;
|
||||
|
||||
/// <summary>
|
||||
/// 过期的时间
|
||||
/// </summary>
|
||||
public long ExpireTime;
|
||||
|
||||
public bool isDie
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
257
GlobalSever/MQ/WaitBeMsg.cs
Normal file
257
GlobalSever/MQ/WaitBeMsg.cs
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 由SharpDevelop创建。
|
||||
* 用户: Administrator
|
||||
* 日期: 2019-01-05
|
||||
* 时间: 14:08
|
||||
*
|
||||
* 要改变这种模板请点击 工具|选项|代码编写|编辑标准头文件
|
||||
*/
|
||||
using MrWu.Debug;
|
||||
using MrWu.RabbitMQ;
|
||||
using RabbitMQ.Client;
|
||||
using Server.Pack;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using GameData;
|
||||
|
||||
namespace Server.MQ {
|
||||
/// <summary>
|
||||
/// 等待处理的消息
|
||||
/// </summary>
|
||||
public class WaitBeMsg {
|
||||
|
||||
///// <summary>
|
||||
///// 查慢的原因用的,日志
|
||||
///// </summary>
|
||||
//public DateTime logTime;
|
||||
|
||||
// private ServerHead mhead;
|
||||
/// <summary>
|
||||
/// 消息内容
|
||||
/// </summary>
|
||||
public PackHead head;
|
||||
|
||||
/// <summary>
|
||||
/// 包体数据
|
||||
/// </summary>
|
||||
public string jsondata;
|
||||
|
||||
/// <summary>
|
||||
/// 包头+包体
|
||||
/// </summary>
|
||||
public string jsonmessage {
|
||||
get {
|
||||
return message.bodystr;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 其他参数
|
||||
/// </summary>
|
||||
public List<object> pms;
|
||||
|
||||
/// <summary>
|
||||
/// 步骤
|
||||
/// </summary>
|
||||
public int step = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 消息
|
||||
/// </summary>
|
||||
public Message message;
|
||||
|
||||
/// <summary>
|
||||
/// 是否处理完自动确认 如果不是自动确认的话,消息需要手动确认,请清理消息内存
|
||||
/// </summary>
|
||||
public bool AutoAck;
|
||||
|
||||
/// <summary>
|
||||
/// 交换机
|
||||
/// </summary>
|
||||
public string exchange {
|
||||
get {
|
||||
return message.exchange;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 路由键
|
||||
/// </summary>
|
||||
public string routingkey {
|
||||
get {
|
||||
return message.routingkey;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息属性
|
||||
/// </summary>
|
||||
public IBasicProperties propertis {
|
||||
get {
|
||||
return message.propertis;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户数据
|
||||
/// </summary>
|
||||
public IDictionary<string, object> userData {
|
||||
get {
|
||||
return message.userData;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否不需要确认
|
||||
/// </summary>
|
||||
public bool noAck {
|
||||
get {
|
||||
return message.noAck;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息唯一id
|
||||
/// </summary>
|
||||
public string id {
|
||||
get {
|
||||
return message.id;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 消息投递标签
|
||||
/// </summary>
|
||||
public ulong deliveryTag {
|
||||
get {
|
||||
return message.deliveryTag;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否被重复接收过
|
||||
/// </summary>
|
||||
public bool redelivered {
|
||||
get {
|
||||
return message.redelivered;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否确认过
|
||||
/// </summary>
|
||||
public bool isAck {
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否要继续添加到消息列表中处理
|
||||
/// </summary>
|
||||
public bool isAdd;
|
||||
|
||||
/// <summary>
|
||||
/// 数据
|
||||
/// </summary>
|
||||
public object[] datas { get; private set; } = new object[10];
|
||||
|
||||
/// <summary>
|
||||
/// 上次的任务
|
||||
/// </summary>
|
||||
public Task task;
|
||||
|
||||
/// <summary>
|
||||
/// 确认消息
|
||||
/// </summary>
|
||||
/// <param name="mulitple"></param>
|
||||
/// <returns></returns>
|
||||
public bool Ack(bool mulitple = false) {
|
||||
|
||||
if (isAck) {
|
||||
Debug.Warning("消息已被确认过,请勿重复确认!");
|
||||
return false;
|
||||
}
|
||||
|
||||
isAck = true;
|
||||
|
||||
return message.Ack(mulitple);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否被拒绝确认
|
||||
/// </summary>
|
||||
/// <param name="mulitple">是否多条消息</param>
|
||||
/// <param name="requeue">是否重新入列</param>
|
||||
/// <returns></returns>
|
||||
public bool NAck(bool mulitple = false, bool requeue = false) {
|
||||
|
||||
if (isAck) {
|
||||
Debug.Warning("消息已被确认过,请勿重复确认!");
|
||||
return false;
|
||||
}
|
||||
|
||||
isAck = true;
|
||||
|
||||
return message.NAck(mulitple, requeue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空数据
|
||||
/// </summary>
|
||||
internal void Clear() {
|
||||
MessagePool.PutMessage(ref message);
|
||||
isAck = false;
|
||||
step = 0;
|
||||
isAdd = false;
|
||||
this.head = null;
|
||||
this.jsondata = null;
|
||||
this.pms = null;
|
||||
this.task = null;
|
||||
int len = datas.Length;
|
||||
for (int i = 0; i < len; i++) {
|
||||
datas[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public WaitBeMsg() {
|
||||
//this.message = msg;
|
||||
//jsondata = JsonPack.GetPackHead(msg.bodystr, out head);
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
///// <param name="msg"></param>
|
||||
///// <param name="ack"></param>
|
||||
//public WaitBeMsg(BasicGetResult msg, bool ack) {
|
||||
// this.deliverytag = msg.DeliveryTag;
|
||||
// jsonmessage = Encoding.UTF8.GetString(msg.Body);
|
||||
// jsondata = JsonPack.GetPackHead(jsonmessage, out head);
|
||||
// this.exchange = msg.Exchange;
|
||||
// this.routingKey = msg.Exchange;
|
||||
// this.ack = ack;
|
||||
//}
|
||||
|
||||
///// <summary>
|
||||
/////
|
||||
///// </summary>
|
||||
///// <param name="deliverytag"></param>
|
||||
///// <param name="body"></param>
|
||||
///// <param name="exchange"></param>
|
||||
///// <param name="routingkey"></param>
|
||||
///// <param name="ack"></param>
|
||||
//public WaitBeMsg(ulong deliverytag, byte[] body, string exchange, string routingkey, bool ack) {
|
||||
// this.deliverytag = deliverytag;
|
||||
// jsonmessage = Encoding.UTF8.GetString(body);
|
||||
// jsondata = JsonPack.GetPackHead(jsonmessage, out head);
|
||||
// this.exchange = exchange;
|
||||
// this.routingKey = routingkey;
|
||||
// this.ack = ack;
|
||||
//}
|
||||
}
|
||||
}
|
||||
58
GlobalSever/MQ/WaitBeMsgPool.cs
Normal file
58
GlobalSever/MQ/WaitBeMsgPool.cs
Normal file
@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using MrWu.RabbitMQ;
|
||||
using Server.Pack;
|
||||
using GameData;
|
||||
|
||||
namespace Server.MQ {
|
||||
/// <summary>
|
||||
/// 消息池
|
||||
/// </summary>
|
||||
public class WaitBeMsgPool {
|
||||
static WaitBeMsgPool() {
|
||||
instace = new WaitBeMsgPool();
|
||||
}
|
||||
|
||||
private WaitBeMsgPool() {
|
||||
}
|
||||
|
||||
private static WaitBeMsgPool instace;
|
||||
|
||||
/// <summary>
|
||||
/// 所有的消息
|
||||
/// </summary>
|
||||
private ConcurrentQueue<WaitBeMsg> msgs = new ConcurrentQueue<WaitBeMsg>();
|
||||
|
||||
/// <summary>
|
||||
/// 获取消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static WaitBeMsg GetWaiteBeMsg(Message msg) {
|
||||
WaitBeMsg tmp = null;
|
||||
if (!instace.msgs.TryDequeue(out tmp)) {
|
||||
tmp = new WaitBeMsg();
|
||||
}
|
||||
|
||||
tmp.message = msg;
|
||||
tmp.AutoAck = true;
|
||||
//ServerHead head = null;
|
||||
tmp.jsondata = JsonPack.GetPackHead(msg.bodystr, out tmp.head);
|
||||
//tmp.head = head;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理消息
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static void PutWaiteBeMsg(ref WaitBeMsg msg) {
|
||||
if (msg == null)
|
||||
return;
|
||||
msg.Clear();
|
||||
instace.msgs.Enqueue(msg);
|
||||
msg = null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
BIN
GlobalSever/MQ/服务器集群消息设计图.png
Normal file
BIN
GlobalSever/MQ/服务器集群消息设计图.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Reference in New Issue
Block a user