using System.Threading.Tasks;
using BinaryProtocol.Core.Tcp;
namespace BinaryProtocol.Core.Handles
{
public interface IMessageHandle
{
/// <summary>
/// 解释
/// </summary>
void Resolve(byte[] messageBodyBytes);
/// <summary>
/// 消费
/// </summary>
/// <param name="connectContext"></param>
Task ConsumeAsync(ConnectContext connectContext);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using BinaryProtocol.Core.Models;
using BinaryProtocol.Core.Tcp;
namespace BinaryProtocol.Core.Handles
{
/// <summary>
/// 消息分发器
/// </summary>
public class MessageDispatcher
{
private static List<MessageHandleMapper> _messageHandleMappers = new List<MessageHandleMapper>();
public static IReadOnlyCollection<MessageHandleMapper> MessageHandleMappers => _messageHandleMappers;
/// <summary>
/// 注册消息处理器
/// </summary>
/// <param name="mapper"></param>
public static void RegisterMessageHandleMapper(MessageHandleMapper mapper)
{
if (_messageHandleMappers.Any(r => r.ProtocolType == mapper.ProtocolType && r.MessageType == mapper.MessageType))
{
return;
}
_messageHandleMappers.Add(mapper);
}
public static void Dispatch(MessageHead head, byte[] msgBodyBytes, ConnectContext connectContext)
{
//开启一个子任务来处理消息
Task task = new Task(() =>
{
var mapper = MessageHandleMappers.FirstOrDefault(r =>
r.ProtocolType == head.ProtocolType
&& r.MessageType == head.MessageType);
if (mapper == null)
{
return;
}
//为了防止死锁,每个消息都new一个处理器
var handle = (IMessageHandle)Activator.CreateInstance(mapper.HandleType);
//解释消息体
handle.Resolve(msgBodyBytes);
//消费消息
handle.ConsumeAsync(connectContext);
});
task.Start();
}
}
}
using System.Threading.Tasks;
using BinaryProtocol.Core.Models;
using BinaryProtocol.Core.Tcp;
namespace BinaryProtocol.Core.Handles
{
/// <summary>
/// 消息处理器
/// </summary>
public abstract class MessageHandle<T> : IMessageHandle
{
protected MessageBody<T> MessageBody { get; private set; }
public virtual void Resolve(byte[] messageBodyBytes)
{
//获取消息字段配置信息
MessageBody = new MessageBody<T>(messageBodyBytes);
}
/// <summary>
/// 消费消息,抽象方法
/// </summary>
/// <param name="connectContext"></param>
public abstract Task ConsumeAsync(ConnectContext connectContext);
}
}
using System;
namespace BinaryProtocol.Core.Handles
{
/// <summary>
/// 消息处理器映射器
/// </summary>
public class MessageHandleMapper
{
/// <summary>
/// 处理器类型
/// </summary>
public Type HandleType { get; }
/// <summary>
/// 协议类型
/// </summary>
public byte ProtocolType { get; }
/// <summary>
/// 消息类型
/// </summary>
public byte MessageType { get; }
public MessageHandleMapper(
byte protocolType,
byte messageType,
Type handleType)
{
HandleType = handleType;
ProtocolType = protocolType;
MessageType = messageType;
}
}
}
using System;
using System.Threading.Tasks;
using BinaryProtocol.Core.Constants;
using BinaryProtocol.Core.Events;
using BinaryProtocol.Core.Models;
using BinaryProtocol.Core.Tcp;
namespace BinaryProtocol.Core.Handles
{
public class SysMessageHandle : MessageHandle<MessageEvent>
{
public override async Task ConsumeAsync(ConnectContext connectContext)
{
switch (MessageBody.Value.Command)
{
//客户端连接
case (byte)Command.Connect:
SignActive(connectContext);
connectContext.LogAction($"收到客户端{connectContext.ClientId}的连接请求");
connectContext.ClientId = MessageBody.Value.ClientId;
Message<MessageEvent> msg = SysMessageBuilder.CreateConnectResultMessage(MessageBody.Value.ClientId);
await connectContext.TcpServer.SendAsync(MessageBody.Value.ClientId, msg);
break;
case (byte)Command.ConnectResult:
SignActive(connectContext);
connectContext.LogAction($"{connectContext.ClientId}收到服务器的连接响应");
break;
case (byte)Command.HeartBeat:
SignActive(connectContext);
connectContext.LogAction($"收到{connectContext.ClientId}心跳包");
var heartBeatMsg = SysMessageBuilder.CreateHeartBeatResultMessage(MessageBody.Value.ClientId);
await connectContext.TcpServer.SendAsync(MessageBody.Value.ClientId, heartBeatMsg);
break;
case (byte)Command.HeartBeatResult:
SignActive(connectContext);
connectContext.LogAction($"{connectContext.ClientId}收到心跳包响应");
break;
}
}
/// <summary>
/// 标记活动状态
/// </summary>
/// <param name="connectContext"></param>
private void SignActive(ConnectContext connectContext)
{
connectContext.LastActiveTime = DateTime.Now;
connectContext.IsClientActive = true;
}
}
}