贵港网站建设兼职,网站建设及推广费用怎么入账,小程序推广,wordpress远程后台设置题图来自https://www.pexels.com/概述在传统企业级开发中#xff0c;消息队列机制已经成为一种非常常见的技术实现手段#xff0c;而基于NetMQ则看起来有点像一朵“奇葩”#xff0c;看起来从名字似乎是一个消息队列#xff08;Message Quene#xff09;#xff0c;但事实… 题图来自https://www.pexels.com/ 概述在传统企业级开发中消息队列机制已经成为一种非常常见的技术实现手段而基于NetMQ则看起来有点像一朵“奇葩”看起来从名字似乎是一个消息队列Message Quene但事实上更多的却是一个类似于socket机制的消息库。它虽然提供了消息队列的能力但又与传统消息队列中间件如kafka、rabbitmq等有一定的区别。不过不管它是啥它提供的一些类似于消息队列的机制使得开发者能够快速在项目中使用起来例如类似于发布订阅模式、推拉模式等机制接入简便功能也挺强大。而且当如果我们要实现消息加密时还可能通过一些简单的操作实现例如我们可以选择对内容进行Rsa加密或者也许还有其他的实现方法TL;DR:本文首先介绍NETMQ及其常用的使用模式进而讨论如何基于NETMQ实现消息的加密传输机制。NetMq简介和基本特性ZeroMQNETMQ是一种轻量级的消息队列组件是著名的ZeroMQ的重要成员。2010年AMQP的最初设计者Pieter Hintjens带领其团队退出了该开源项目并发起成立了ZeroMQ这个新的消息库并发展至今。Pieter Hintjens 后由于胆管癌复发于2016年接受了安乐死。在ZeroMQ的官方网站中其介绍到ZeroMQ看起来似乎是一个消息队列框架实际上更像一个并发处理框架。它除了提供了多种消息队列机制如Pub-Sub、Pull-Push、Dealer、XPub-XSub机制外更是为开发者提供了跨多种传输能力的套接字它不仅适用于进程间的消息传输也同样适用于进程内、TCP和多播的传输机制基于其提供的框架开发者能快速的实现原子消息的传输能力。ZeroMQ的轻量级体现在其框架灵活简单性能优异无需依赖外部组件即可轻松实现优秀的性能。它也支持异步I/O的传输机制可为多核应用程序提供扩展且能成为集群部署的核心传输组件。ZeroMQ提供了多种语言实现参见其官方网站包括C语言C#Java等主流后端语言都支持良好同样也支持包括Go、Node.JS等最近比较热门的新兴语言。ZeroMQ自然也支持不同语言间的数据传输使其可以成为跨语言传输的一种消息协议。ZeroMQ的Zero代表一种极简文化可以代表零代理层与Mqtt等队列机制不同ZeroMQ提供的是一种无代理层的队列机制零延迟零成本和零管理。ZeroMQ致力于打造极简的通信组件通过消除组件的复杂性来提升其功能应用效果。NETMQ和ClrZmq对于C#开发者来说可以使用NetMQ和ClrZmq两种不同的方式来获得ZeroMQ的魔力前者是基于C#语言原生实现的ZeroMQ通信协议后者则是通过C#调用基于C语言实现 的Libzmq库来使用。相对而言前者可能更受欢迎。NETMQ也同样继承了ZeroMQ的优雅性能和轻量化开发者可通过Nuget下载NetMQ的的组件通过几行代码就可以集成消息队列和套接字传输能力。如图所示NetMQ获得了约175w的下载量算是一个比较受欢迎的基础组件。而同样在nuget上ClrZmq的下载量则远远少于NetMQ仅仅8w多的下载量可能说明它只是一种小众框架吧。值得一提的是ClrZmq需要根据构建平台来选择不同的架构。NETMQ的组成部分截止本文撰写时NETMQ的版本为4.0.1.6作为轻量级组件的一个评判标准依赖项复杂度也是个重要指标而NetMQ只依赖了AsyncIO、NaCI.NET、System.ServiceModel.Primitives、System.Threading.Tasks.Extension、System.ValueTuple五个组件算是名副其实此处重点介绍两个非System开头的组件。AsyncIO该组件是一个高性能的异步的消息套接字库事实上在Nuget上该消息库比NetMQ更受欢迎基于该组件可减少套接字开发的成本。NaCI该组件是一个加密组件实现了包括Curve25519x、Salsa20、Poly1305加密算法。Curve25519是一种椭球曲线加密算法被设计用于椭圆曲线迪菲-赫尔曼ECDH密钥交换方法。Salsa20是一种流加密算法。Poly1305是一种消息认证码可用于检测消息的完整性和验证消息的真实性现常在网络安全协议SSL/TLS中与salsa20或ChaCha20流密码结合使用。这三种算法都是由密码专家丹尼尔·J·伯恩斯坦设计的加密算法。这两个组件都是由NETMQ的创建者somdoron[1]Doron Somech创建并引入到NETMQ中。官方网站NETMQ官方网站地址为https://netmq.readthedocs.io/该网站提供了较为完整的学习示例开发者可参考该示例快速学会该组件的用法。常见模式实现NETMQ提供了多种消息通信机制例如发布订阅模式推拉模式发布订阅模式Pulish-Subscriber Pattern简介发布-订阅是一种消息传递模式其中消息的发送者称为发布者不会将消息编程为直接发送给特定的接收者称为订阅者。发布的消息按照主题进行特征化作为发布者事先不用知道可能有哪些订阅者如果有。类似地订阅者可订阅多个主题也可只订阅一个主题。订阅者也同样无需关注发布者是否真实存在不过由于ZeroMQ本身没有代理层且需要绑定服务端端口事实上看起来似乎必须给定发布者。但由于ZeroMQ本身也可以作为一种微服务架构的基础设施[2]实际上也可以通过一些机制例如消息代理地址代理DNS网关如ZeroConfGossip协议等机制将发布者隐藏在消息网关背后从而使得订阅者无需关注发布者具体在哪里。代码示例该需要首先创建一个发布者并通过主题的形式发布消息。class Program
{private static string _address ;static void Main(string[] args){Console.WriteLine(Hello World!);_address tcp://127.0.0.1:5556; //设置端口var task Task.Factory.StartNew(async() {await BeginPublisherAsync();});var taskSubScriber Task.Factory.StartNew(() { BeginSubscriberSocket();}); while(Console.ReadKey().Key!ConsoleKey.Escape);}/// summary/// 启动消息发布/// /summary/// returns/returnsprivate static async Task BeginPublisherAsync(){using (var publisher new PublisherSocket()){publisher.Bind(_address); //绑定端口while (true){publisher.SendMoreFrame(DotNET技术圈) // Topic.SendFrame(test); // Messageawait Task.Delay(TimeSpan.FromSeconds(1));}}}/// summary/// 订阅消息/// /summaryprivate static void BeginSubscriberSocket(){using (var subscriber new SubscriberSocket()){subscriber.Connect(_address);subscriber.SubscribeToAnyTopic();while (true){var topic subscriber.ReceiveFrameString();var msg subscriber.ReceiveFrameString();Console.WriteLine(收到消息: {0} {1}, topic, msg);}}}
}在上述代码中发布者绑定了tcp://127.0.0.1:5556端口并通过同步阻塞的方式发布主题为Topic的消息内容。也可以指定主机的固定ip地址来进行消息发布还能通过inproc://inproc-demo的方式进行进程内通信。using var subscriber new SubscriberSocket()subscriber.Connect(tcp://127.0.0.1:5556);subscriber.Subscribe(TopicA); //订阅到TopicA主题也可通过SubscribeToAnyTopic订阅所有主题也可通过UnSubcribe取消订阅相关主题while (true)
{var topic subscriber.ReceiveFrameString();var msg subscriber.ReceiveFrameString();Console.WriteLine(From Publisher: {0} {1}, topic, msg);
}请求响应模式Request-Response Pattern)请求响应模式也是NETMQ众多消息模式中最为简单的一种模式这种模式实际上有点像http协议可通过一问一答的同步阻塞的模式进行消息的应答当然发送HTTP请求我们也可以不必接收响应NETMQ的请求响应模式也同样如此。示意图private static void BeginResponseSocket(){using var responseSocket new ResponseSocket(_address);string requestresponseSocket.ReceiveFrameString();responseSocket.SendFrame(Hello DotNET技术圈);} private static async Task BeginRequestSocketAsync()
{using var requestSocket new RequestSocket();requestSocket.Connect(_address);while (requestSocket.TrySignalOK()){try{requestSocket.TrySendFrame(Hallo I am DotNET技术圈码农);requestSocket.TrySendFrame(Hallo I am DotNET技术圈码农); ---这里会引发错误。。}catch(Exception ex){Console.Out.WriteLine(ex);}await Task.Delay(1000);}
}由于该模式的同步阻塞特性如果同时发送两条消息可能会触发NETMQ重复发送异常如推拉模式推拉模式与我们传统意义上理解的类似于手机推送的模式有一些区别ZeroMQ中说该模式主要将消息下发到提供了一组Push-Pull的套接字实现消息下发。值得一提的是即便的同为ZeroMQ模式下不同语言的版本对于相同模式的说明文字描述也不尽相同例如在NetMQ的开发者文档中Well a PushSocket is normally used to push to a PullSocket, whilst the PullSocket will pull from a PushSocket. Sounds obvious right!PushSocket 负责把消息推给PullSocket同样PullSocket负责从PushSocket 拉消息。这样的说明似乎什么都说了但又似乎啥都没说看看其他语言的实现例如基于Python的PyZmq中其描述为这样Push and Pull sockets let you distribute messages to multiple workers, arranged in a pipeline. A Push socket will distribute sent messages to its Pull clients evenly. This is equivalent to producer/consumer model but the results computed by consumer are not sent upstream but downstream to another pull/consumer socket.推拉模式允许你基于通过管道的机制实现消息分发给多个工作者。单个PushSocket分发会将消息均匀的分发给其Pull客户端。这样的操作等效于生产者-消费者模型但消费者计算的结果不是向上发送而是向下游发送到另一个拉/消费者套接字。两种不同的实现在描述上区别还是显著不同通过两者的对比我们可以这样理解Push-Pull模式下两者都可以互为服务端或客户端但无论如何其消息都是单向传输的。消息总是沿着管道向下流动沿着我们设计的方向传输实现消息在不同节点间的负载均衡。例如可以实现如下的效果通过一个Ventilator来生产数据通过多个Pull来拉取数据进而实现数据向下流动可以参考NetMq官方文档来实现该代码。基于推拉模式可以设计非常负责的业务模型例如类似于MapReduce的数据处理器[3]就是一个这样的教学工具。当然该工具只是一个演示ZeroMQ模式实现的分布式计算的Demo可能不适合作为生产用途。代码示意本示例中仅仅简单介绍Push-Pull的用法暂不涉及复杂的模式。private static async Task BeginPushSocketAsync()
{using var pushSocket new PushSocket(_address);while (true){pushSocket.SendFrame(Hello Clients);await Task.Delay(1000);}
}private static async Task BeginPullSocketAsync()
{using var pullSocket new PullSocket(_address);while (true){string message pullSocket.ReceiveFrameString();Console.WriteLine(message);await Task.Delay(1000);}
}netmq加密传输机制实现当我们使用NetMQ进行消息传输时上述示例均没有对消息进行任何加密处理这种策略可能导致一些不可控的安全性风险例如在开发基于NetMQ的聊天室功能时发布的信息若未采取任何加密措施事实上可能意味着消息是以广播的形式对外发布从而会造成某些隐私信息泄漏。或者如果你需要向外Publish某些消息未授权的订阅者订阅了你的数据虽然可能数据中不包含直接的隐私数据但同样可能会引起你的不适。因此从安全性的角度来说无论你计划基于NetMQ实现何种场景事实上可能都得考虑以尽可能安全的形式“发布”你的消息。目前我们可通过三种方式来实现消息的加密传输功能。第一种是使用基于Tls协议的NetMQ.Security组件一种是基于非对称密钥算法如RSA加密算法还有一种是基于ZeroMQ所提供的两种加密方式ECC椭球曲线加密算法和Z85加密算法以对称密钥的方式。基于Tls的NetMq.SecurityNetMQ.Security[4]也是由NetMQ的主要贡献者somdoron开发的组件目前该组件处于不活跃的状态截至目前仅有5次更新上一次更新依然是4年前通过一些早期帖子作者Doron Somech也同样不认为该组件可以在生产环境下使用[5]所以事实上可能不太适合作为专业团队的技术选型。目前比较详细的介绍来自杰哥很忙[6]且优秀的杰哥对fork了该组件的代码[7]并开发了许多功能由于主干仓库已经尘封太久了开发者有兴趣可以参详参详。使用时我们可通过Nuget下载由NetMQ官方发布的组件不过似乎下载量有点惨淡那么此处就不再赘述了。。。。非对称密钥算法-Rsa加密对于文本来说使用Rsa这种非对称算法族进行加密是一种非常常见的选择RSA是由罗纳德·李维斯特[8]Ron Rivest、阿迪·萨莫尔[9]Adi Shamir和伦纳德·阿德曼[10]Leonard Adleman在1977年一起提出的当时他们三人都在麻省理工学院[11]工作。RSA 就是他们三人姓氏开头字母拼在一起组成的。RSA算法的核心是极大整数做因数分解换言之对一极大整数做因式分解越困难RSA算法越可靠。目前传统计算机只能破解较为简单的RSA密钥如果使用的密钥长度足够长理论上用RSA加密的信息也很难以被破解。在RSA算法中密钥由私钥和公钥组成。由私钥负责对内容进行解密并用公钥进行加密。分配公钥的过程必须足够安全若被中间人攻击则可能导致公钥失效。影响RSA密钥安全性的要素首先是其密钥长度目前推荐的RSA算法公钥长度为2048位。其次是RSA密钥的填充模式共有三种填充模式RSA_PKCS1_PADDING RSA_PKCS1_OAEP_PADDING RSA_NO_PADDING。填充技术实现的不好RSA也不会安全应尽量选择最安全的填充模式例如RSA_PKCS1_PADDING。原因如下[12]1.RSA加密是确定的即给定一个密钥特定明文总会映射到特定的密文。攻击者可以根据密文中统计信息获取明文的一些信息。2.填充技术如果比较弱那么较小的明文和小型公开指数e将易于受到攻击。3.RSA有个特性叫做延展性如果攻击者可以将一种密文转换为另一种密文这种新密文会导致对明文的转换变得可知这种特性并没有解密明文而是以一种可预测的方式操纵了明文比如银行交易系统中攻击者根据新密文直接去修改原密文中金额的数据可以在用户和接受方无法感知的情况下进行修改。在RSA算法中提供了以下功能提供[13]•密钥对生成生成随机私钥通常大小为 1024-4096 位和相应的公钥。•加密使用公钥加密秘密消息范围为 [0...key_length] 的整数并使用秘密密钥将其解密。•数字签名签署消息使用私钥并验证消息签名使用公钥。•密钥交换安全地传输一个秘密密钥用于以后的加密通信。RSA 可以使用不同长度的密钥1024、2048、3072、4096、8129、16384 甚至更多位的密钥。3072 位及以上的密钥长度被认为是安全的。更长的密钥提供更高的安全性但消耗更多的计算时间因此需要在安全性和速度之间进行权衡。很长的 RSA 密钥例如 50000 位或 65536 位对于实际使用来说可能太慢例如密钥生成可能需要几分钟到几个小时。网上也有基于RSA进行NetMQ进行消息加密的示例[14]可供参考。其核心流程为在进行消息发送时使用RSA公钥进行加密MsgObject sendmsg EventQueue.Dequeue ( ) ;
sendmsg.Content RSAEncryption.RSAEncrypt(sendmsg.Content);
sendmsg.MachineName msg.MachineName;
SendMessageQueue.Enqueue(sendmsg) ;并在客户端接收到消息后对正文进行RSA解密解密代码略。使用对称密钥加密算法-Ecc加密算法进行消息加密RSA算法虽好但由于私钥由客户端管理公钥由服务端管理且RSA必须密钥位数足够长才安全例如2048位使用这么长的密钥进行加密时间开销也令人吃不消的有没有一种更简单、快速的算法来实现呢使用AES算法我们或许会想到AES算法例如AES256算法这种“对称密钥加密算法[15]”。在“对称密钥加密算法”中加密和解密使用秘密密钥或密码短语从中派生出密钥。该秘密密钥用于加密和解密数据通常是128位或256位并被称为“加密密钥”。有时它以十六进制或 base64 编码的整数形式给出或者通过密码到密钥派生方案派生当输入数据被加密时它被转换为加密的密文当密文被解密时它被转换回原始输入数据。通常对称加密过程使用一系列步骤涉及不同的加密算法密码到密钥派生算法如 Scrypt 或 Argon2允许使用密码而不是密钥并使密码破解变得困难而缓慢。块到流密码转换算法块密码模式如CBC或CTR 消息填充算法如PKCS7 在某些模式下允许使用块密码算法如AES加密任意大小的数据。块密码算法如AES 使用密钥安全地加密固定长度的数据块。消息认证算法如HMAC 检查解密后得到的结果是否与加密前的原始消息匹配。NETMQ的原生解决方案不过上述AES加密算法实质上也需要开发者手工处理消息体存在的内存开销和时间可能对于用户来说依然无法接受或许最好的办法依然是基于NETMQ框架来入手看看是否有什么“原生”的解决方案。所幸ZeroMQ在设计之初就已经将安全作为其认为非常重要的一个方面在这篇博客[16]中ZeroMQ提到了其对于安全层的目标包括•它使用起来必须非常简单而且不可能出错。复杂性是密码学的第一大风险和第一大漏洞。每一个额外的选项都是一种出错的方式最终导致一个不安全的系统。•对于实际工作它必须足够快。如果安全性使系统变得太慢而无法使用人们就会将其关闭因为今天能够工作的务实需求胜过明天被入侵的风险。•它必须基于标准化协议以便任何团队都可以重新实施、独立验证并在软件堆栈之外进行改进。•等等。并从2013年起在ZeroMQ版本4.0.0中就已经引入了安全架构设计包括•一种新的有线协议ZMTP 3.0[17]为所有 ZeroMQ 连接添加了安全握手。•一种新的安全协议CurveZMQ[18]它通过 TCP 连接在两个 ZeroMQ 对等点之间实现“完美的前向安全”。我将在下面解释 CurveZMQ。•ZMTP 的一组安全机制NULL、PLAIN 和 CURVE每个机制都由它们自己的 RFC 描述。NULL 本质上是我们之前所拥有的。PLAIN 允许简单的用户名和密码验证。CURVE 实现了 CurveZMQ 协议。、•等等。在ZeroMQ中集成的椭球曲线算法为Curve25519[19] 目前在我们所使用的NetMQ中也同样集成了该算法。在搞清楚原理后我们再来使用该算法发现一切就变得非常简单明了了。var serverPair NetMQ.NetMQCertificate.CreateFromSecretKey(UTF8Encoding.UTF8.GetBytes(”这里是密钥“));;using var server new PublishSocket();server.Options.CurveServer true;server.Options.CurveCertificate serverPair;server.Bind($tcp://127.0.0.1:55367);using (var server new SubscriberSocket()){var cert NetMQ.NetMQCertificate.CreateFromSecretKey(UTF8Encoding.UTF8.GetBytes(”这里是密钥“));var curveServerCertificate serverPair;var clientCertificate new NetMQCertificate(); ---这里是客户端密钥server.Options.CurveServerCertificate curveServerCertificate; ---这里是使用服务端密钥server.Options.CurveCertificate clientCertificate; ---这里是客户端密钥}结语本文对NetMQ进行了简单的概述包括其常见模式和加密传输机制开发者若有兴趣可通过NetMQ官网获得更多学习资料。如果开发者加密算法感兴趣还可以通过这个网站(https://cryptobook.nakov.com读到许多有关加密的基础知识。References[1] somdoron: https://github.com/somdoron[2] 微服务架构的基础设施: https://zguide.zeromq.org/docs/chapter8/[3] 类似于MapReduce的数据处理器: https://github.com/sdiehl/kaylee[4] NetMQ.Security: https://github.com/NetMQ/NetMQ.Security[5] 同样不认为该组件可以在生产环境下使用: https://groups.google.com/g/netmq-dev/c/3tcsLvxUWgc[6] 杰哥很忙: https://www.cnblogs.com/Jack-Blog/p/9015783.html[7] 该组件的代码: https://github.com/GuojieLin/NetMQ.Security[8] 罗纳德·李维斯特: https://zh.wikipedia.org/wiki/罗纳德·李维斯特[9] 阿迪·萨莫尔: https://zh.wikipedia.org/wiki/阿迪·萨莫尔[10] 伦纳德·阿德曼: https://zh.wikipedia.org/wiki/伦纳德·阿德曼[11] 麻省理工学院: https://zh.wikipedia.org/wiki/麻省理工学院[12] 原因如下: https://blog.csdn.net/makenothing/article/details/88429511[13] 以下功能提供: https://cryptobook.nakov.com/asymmetric-key-ciphers/the-rsa-cryptosystem-concepts[14] 消息加密的示例: https://blog.actorsfit.in/a?ID01400-85ae6267-6c93-41e3-b06b-5d9792a422ba/[15] 对称密钥加密算法: https://cryptobook.nakov.com/symmetric-key-ciphers[16] 这篇博客: https://jaxenter.com/using-zeromq-security-part-1-119346.html[17] ZMTP 3.0: http://zmtp.org/[18] CurveZMQ: http://curvezmq.org/[19] Curve25519: http://cr.yp.to/ecdh.html