企业级工作流解决方案(七)--微服务Tcp消息传输模型之消息编解码
Tcp消息传输主要参照surging来做的,做了部分裁剪和改动,详细参见:https://github.com/dotnetcore/surging
Json-rpc没有定义消息如何传输,因此,Json-Rpc RpcRequest对象和RpcResponse对象需要一个传输载体,这里的传输对象主是TransportMessage,如下代码,这里的Content请求时为RcpRequest对象,答复时为RpcResponse对象,答复时Header一般情况下为空。
/// <summary>
/// 传输消息模型。
/// </summary>
public class TransportMessage
{ public TransportMessage()
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TransportMessage(object content,object headers)
{
if (content == null)
throw new ArgumentNullException(nameof(content)); Content = content;
Headers = headers;
ContentType = content.GetType().FullName;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public TransportMessage(object content, object headers, string fullName)
{
if (content == null)
throw new ArgumentNullException(nameof(content)); Headers = headers;
Content = content;
ContentType = fullName;
} /// <summary>
/// 消息Id。
/// </summary>
public string Id { get; set; } /// <summary>
/// 消息内容。
/// </summary>
public object Content { get; set; } /// <summary>
/// 消息传输Header
/// </summary>
public object Headers { get; set; } /// <summary>
/// 内容类型。
/// </summary>
public string ContentType { get; set; } /// <summary>
/// 是否调用消息。
/// </summary>
/// <returns>如果是则返回true,否则返回false。</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInvokeMessage()
{
return ContentType == MessagePackTransportMessageType.jsonRequestTypeName;
} /// <summary>
/// 是否是调用结果消息。
/// </summary>
/// <returns>如果是则返回true,否则返回false。</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInvokeResultMessage()
{
return ContentType == MessagePackTransportMessageType.jsonResponseTypeName;
} /// <summary>
/// 获取内容。
/// </summary>
/// <typeparam name="T">内容类型。</typeparam>
/// <returns>内容实例。</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T GetContent<T>()
{
return (T)Content;
} /// <summary>
/// 获取Header。
/// </summary>
/// <typeparam name="T">Header类型。</typeparam>
/// <returns>Header实例。</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T GetHeaders<T>()
{
return (T)Headers;
} /// <summary>
/// 创建一个调用传输消息。
/// </summary>
/// <param name="invokeMessage">调用实例。</param>
/// <returns>调用传输消息。</returns>
public static TransportMessage CreateInvokeMessage(JsonRequest invokeMessage,NameValueCollection nameValueCollection)
{
return new TransportMessage(invokeMessage, nameValueCollection, MessagePackTransportMessageType.jsonRequestTypeName)
{
Id = Guid.NewGuid().ToString("N")
};
} /// <summary>
/// 创建一个调用结果传输消息。
/// </summary>
/// <param name="id">消息Id。</param>
/// <param name="invokeResultMessage">调用结果实例。</param>
/// <returns>调用结果传输消息。</returns>
public static TransportMessage CreateInvokeResultMessage(string id, JsonResponse jsonResponse,NameValueCollection nameValueCollection)
{
return new TransportMessage(jsonResponse, nameValueCollection, MessagePackTransportMessageType.jsonResponseTypeName)
{
Id = id
};
}
}
TransportMessage需要在dotnetty中传输,则需要对TransportMessage进行编码解码
消息编解码器
public interface ITransportMessageEncoder
{
byte[] Encode(TransportMessage message);
}
public interface ITransportMessageDecoder
{
TransportMessage Decode(byte[] data);
}
Json编解码
平时编码中经常用的方式
public sealed class JsonTransportMessageEncoder : ITransportMessageEncoder
{
#region Implementation of ITransportMessageEncoder public byte[] Encode(TransportMessage message)
{
var content = JsonConvert.SerializeObject(message);
return Encoding.UTF8.GetBytes(content);
} #endregion Implementation of ITransportMessageEncoder
} public sealed class JsonTransportMessageDecoder : ITransportMessageDecoder
{
#region Implementation of ITransportMessageDecoder public TransportMessage Decode(byte[] data)
{
var content = Encoding.UTF8.GetString(data);
var message = JsonConvert.DeserializeObject<TransportMessage>(content);
if (message.IsInvokeMessage())
{
message.Content = JsonConvert.DeserializeObject<JsonRequest>(message.Content.ToString());
}
if (message.IsInvokeResultMessage())
{
message.Content = JsonConvert.DeserializeObject<JsonResponse>(message.Content.ToString());
}
return message;
} #endregion Implementation of ITransportMessageDecoder
}
MessagePack
官网地址:https://msgpack.org/
贴出代码,不过多的解释
[MessagePackObject]
public class MessagePackTransportMessage
{
public MessagePackTransportMessage(TransportMessage transportMessage)
{
Id = transportMessage.Id;
ContentType = transportMessage.ContentType; object contentObject;
if (transportMessage.IsInvokeMessage())
{
contentObject = new MessagePackJsonRequest(transportMessage.GetContent<JsonRequest>());
}
else if (transportMessage.IsInvokeResultMessage())
{
contentObject = new MessagePackJsonResponse(transportMessage.GetContent<JsonResponse>());
}
else
{
throw new NotSupportedException($"无法支持的消息类型:{ContentType}!");
} Content = SerializerUtilitys.Serialize(contentObject); var headersObject = transportMessage.GetHeaders<NameValueCollection>(); Headers = SerializerUtilitys.Serialize(JsonConvert.SerializeObject(MessagePackTransportMessageType.NvcToDictionary(headersObject)));
} public MessagePackTransportMessage()
{
} [Key(0)]
public string Id { get; set; } [Key(1)]
public byte[] Content { get; set; } [Key(2)]
public byte[] Headers { get; set; } [Key(3)]
public string ContentType { get; set; } [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInvokeMessage()
{
return ContentType == MessagePackTransportMessageType.jsonRequestTypeName;
} [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool IsInvokeResultMessage()
{
return ContentType == MessagePackTransportMessageType.jsonResponseTypeName;
} public TransportMessage GetTransportMessage()
{
var message = new TransportMessage
{
ContentType = ContentType,
Id = Id,
Content = null,
Headers = null,
}; object contentObject;
if (IsInvokeMessage())
{
contentObject =
SerializerUtilitys.Deserialize<MessagePackJsonRequest>(Content).GetJsonRequest();
}
else if (IsInvokeResultMessage())
{
contentObject =
SerializerUtilitys.Deserialize<MessagePackJsonResponse>(Content)
.GetJsonResponse();
}
else
{
throw new NotSupportedException($"无法支持的消息类型:{ContentType}!");
}
message.Content = contentObject;
var headers = SerializerUtilitys.Deserialize<string>(Headers);
message.Headers = JsonConvert.DeserializeObject(headers);
return message;
}
} public sealed class MessagePackTransportMessageEncoder:ITransportMessageEncoder
{
#region Implementation of ITransportMessageEncoder [MethodImpl(MethodImplOptions.AggressiveInlining)]
public byte[] Encode(TransportMessage message)
{
var transportMessage = new MessagePackTransportMessage(message)
{
Id = message.Id,
ContentType = message.ContentType,
};
return SerializerUtilitys.Serialize(transportMessage);
}
#endregion Implementation of ITransportMessageEncoder
} public sealed class MessagePackTransportMessageDecoder : ITransportMessageDecoder
{
#region Implementation of ITransportMessageDecoder [MethodImpl(MethodImplOptions.AggressiveInlining)]
public TransportMessage Decode(byte[] data)
{
var message = SerializerUtilitys.Deserialize<MessagePackTransportMessage>(data);
return message.GetTransportMessage();
} #endregion Implementation of ITransportMessageDecoder
}
ProtoBuffer
这个应该听得比较多
[ProtoContract]
public class ProtoBufferTransportMessage
{
public ProtoBufferTransportMessage(TransportMessage transportMessage)
{
Id = transportMessage.Id;
ContentType = transportMessage.ContentType; object contentObject;
if (transportMessage.IsInvokeMessage())
{
contentObject = new ProtoBufferJsonRequest(transportMessage.GetContent<JsonRequest>());
}
else if (transportMessage.IsInvokeResultMessage())
{
contentObject = new ProtoBufferJsonResponse(transportMessage.GetContent<JsonResponse>());
}
else
{
throw new NotSupportedException($"无法支持的消息类型:{ContentType}!");
} Content = SerializerUtilitys.Serialize(contentObject);
Headers = SerializerUtilitys.Serialize(transportMessage.GetHeaders<NameValueCollection>());
} public ProtoBufferTransportMessage()
{
} [ProtoMember(1)]
public string Id { get; set; } [ProtoMember(2)]
public byte[] Content { get; set; } [ProtoMember(3)]
public byte[] Headers { get; set; } [ProtoMember(4)]
public string ContentType { get; set; } public bool IsInvokeMessage()
{
return ContentType == MessagePackTransportMessageType.jsonRequestTypeName;
} public bool IsInvokeResultMessage()
{
return ContentType == MessagePackTransportMessageType.jsonResponseTypeName;
} public TransportMessage GetTransportMessage()
{
var message = new TransportMessage
{
ContentType = ContentType,
Id = Id,
Content = null,
Headers = null,
}; object contentObject;
if (IsInvokeMessage())
{
contentObject =
SerializerUtilitys.Deserialize<ProtoBufferJsonRequest>(Content).GetJsonRequest();
}
else if (IsInvokeResultMessage())
{
contentObject =
SerializerUtilitys.Deserialize<ProtoBufferJsonResponse>(Content)
.GetJsonResponse();
}
else
{
throw new NotSupportedException($"无法支持的消息类型:{ContentType}!");
} message.Content = contentObject;
message.Headers = SerializerUtilitys.Deserialize<NameValueCollection>(Headers); return message;
}
} public sealed class ProtoBufferTransportMessageEncoder : ITransportMessageEncoder
{
#region Implementation of ITransportMessageEncoder public byte[] Encode(TransportMessage message)
{
var transportMessage = new ProtoBufferTransportMessage(message)
{
Id = message.Id,
ContentType = message.ContentType,
}; return SerializerUtilitys.Serialize(transportMessage);
} #endregion Implementation of ITransportMessageEncoder
} public sealed class ProtoBufferTransportMessageDecoder : ITransportMessageDecoder
{
#region Implementation of ITransportMessageDecoder public TransportMessage Decode(byte[] data)
{
var message = SerializerUtilitys.Deserialize<ProtoBufferTransportMessage>(data);
return message.GetTransportMessage();
} #endregion Implementation of ITransportMessageDecoder
}
企业级工作流解决方案(七)--微服务Tcp消息传输模型之消息编解码的更多相关文章
- 企业级工作流解决方案(八)--微服务Tcp消息传输模型之服务端处理
服务端启动 服务端启动主要做几件事情,1. 从配置文件读取服务配置(主要是服务监听端口和编解码配置),2. 注册编解码器工厂,3. 启动dotnetty监听端口,4. 读取配置文件,解析全局消息处理模 ...
- 企业级工作流解决方案(六)--微服务消息处理模型之与Abp集成
身份认证传递 对于Abp比较熟悉的朋友应该对他里面的用户身份认证比较熟悉,他是通过实现微软提供的权限认证方式实现的,用户登录身份信息存储在System.Security.Claims.ClaimsPr ...
- .NET Core微服务之基于EasyNetQ使用RabbitMQ消息队列
Tip: 此篇已加入.NET Core微服务基础系列文章索引 一.消息队列与RabbitMQ 1.1 消息队列 “消息”是在两台计算机间传送的数据单位.消息可以非常简单,例如只包含文本字符串:也可以更 ...
- [手把手教你] 用Swoft 搭建微服务(TCP RPC)
序言 Swoft Framework 基于 Swoole 原生协程的新时代 PHP 全栈式协程框架 Swoft 是什么? Swoft 框架是首个基于Swoole 原生协程的新时代 PHP高性能协程全栈 ...
- 微服务SpringCloud之配置中心和消息总线
在微服务SpringCloud之Spring Cloud Config配置中心SVN博客中每个client刷新配置信息时需要post请求/actuator/refresh,但客户端越来越多时,,需要每 ...
- 企业级工作流解决方案(十一)--集成Abp和ng-alain--权限系统服务
权限系统主要定义为管理员增删改查权限数据,直接读取数据库,权限系统服务主要定义为供其他系统调用的权限验证接口,定义为两个不同的微服务. 权限系统有一个特点,数据变动比较小,数据量本身并不是很大,访问量 ...
- 企业级工作流解决方案(九)--微服务Tcp消息传输模型之客户端处理
客户端启动 客户端启动主要做三件事情,1. 从配置文件读取服务调用配置,存储到全局对象中.2. 指定客户端编解码器工厂.3. 预连接,即预先建立与服务端的通信Chanel. [DependsOn(ty ...
- 企业级工作流解决方案(十五)--集成Abp和ng-alain--Abp其他改造
配置功能增强 Abp定义了各种配置接口,但是没有定义这些配置数据从哪里来,但是管理配置数据对于一个应用程序来说,是必不可少的一件事情. .net的配置数据管理,一般放在Web.config文件或者Ap ...
- 企业级工作流解决方案(十四)--集成Abp和ng-alain--自动化脚本
对于.net方向,做过自动化的,应该没有人不熟悉msbuild吧,非常强大的代码编译工具,.net平台的编译工作都是交给他来完成的,包括.net core的命令,本质上都是调用msbuild来执行的 ...
随机推荐
- Hugo+Github 搭建个人博客(Windows环境下)
目录 Hugo+Github 搭建个人博客(Windows环境下) 1.前言 2.Differences 2.1 https vs SSH 2.2 新建的github的仓库名必须为 用户名+githu ...
- 实战:xfs文件系统的备份和恢复
概述 XFS提供了 xfsdump 和 xfsrestore 工具协助备份XFS文件系统中的数据.xfsdump 按inode顺序备份一个XFS文件系统. centos7选择xfs格式作为默认文件系统 ...
- 【垃圾回收-CMS】Java内存回收实践经验 防止内存报警
jdk6和7服务器端(-server) 默认的新生代的垃圾回收器为:PS Scavenge,老年代默认的垃圾回收器为:PS MarkSweep 目前项目使用了jdk7,tomcat7,经常出现内存堆使 ...
- [String] intern()方法
intern()方法设计的初衷,就是重用String对象,以节省内存消耗. JDK1.6以及以前版本中,常量池是放在 Perm 区(属于方法区)中的,熟悉JVM的话应该知道这是和堆区完全分开的. 使用 ...
- ATOM基础教程一使用前端插件emmet(16)
emmet简介 http://blog.csdn.net/zsl10/article/details/51956791 emmet的前身是Zen coding,从事Web前端开发的工程师对该插件并不陌 ...
- 基于gin的golang web开发:模型绑定
在前两篇文章介绍路由的时候,我们了解到gin可用通过类似DefaultQuery或DefaultPostForm等方法获取到前端提交过来的参数.参数不多的情况下也很好用,但是想想看,如果接口有很多个参 ...
- 4G DTU的使用方法和应用领域
4G DTU是一种数据传输单元,通俗理解就是,用来传输数据的一种硬件.既然是用来传输数据的,那就能将它视为一个管道,也就是说,指令同过它传给设备,而管道是不对这些指令做出响应的. 4G DTU如何使用 ...
- Struts2 S2-059 (CVE-2019-0230 )复现 及流量分析、特征提取
一.简介 2020年08月13日,Apache官方发布了Struts2远程代码执行漏洞的风险通告,该漏洞编号为CVE-2019-0230,漏洞等级:高危,漏洞评分:8.5 二.漏洞描述 Struts2 ...
- 对Python"一切皆对象"的小参悟
写在前面 若有误区请大神不吝指正,以免带偏了如我者的弱鸡们 据闻对此不再懵逼后,于函数以及高阶函数编程的进阶有益 类:又称对象,由类创建的个体被称为实例 名言名句"一切皆对象(一切皆类,一切 ...
- 动态规划之KMP字符匹配算法
KMP 算法(Knuth-Morris-Pratt 算法)是一个著名的字符串匹配算法,效率很高,但是确实有点复杂. 很多读者抱怨 KMP 算法无法理解,这很正常,想到大学教材上关于 KMP 算法的讲解 ...