标准化模块接口--统一消息

本来今晚想写如何搞动态加载和动态补丁的,但很不幸,翻遍了硬盘,也没找到以前的代码,连网盘里都没备份。这时候,才焕然大悟--半年前我换上现在的笔记本,淘汰了那台老掉牙的台式机。所幸硬盘没丢,不过一时时也没法读里面的数据了。等过些日子,读出里面的数据再谈动态加载和动态补丁技术。今天说些简单的,能在软件设计中立即用得上的,模块间通信技术--统一消息。

统一消息模型,最早的启发是UT的Wacos SSI。那是一个很不错的通信模型,允许模块间的通信统一成队列通信;而在物理上,模块可能位于各种网络中的不同的实体,又或者是不同的进程,线程。记得那会调试核心网的程序,在板卡上是没有什么调试环境的,除了WindShell(同CSHELL)外,就没什么支撑了。于是我们就把软件用GDB加载到目标机(无盘工作站),然后开始测试。有人不理解了,这没啥啊!现实是这价值很大,大型系统的嵌入式开发,能争取到的机房空间、设备和板卡总是奇缺,就当时的情况来说,我们三四个人才能分到一套设备。Wacos_SSI的队列通信技术,让我们可以把目标机做成功能板块,且只需要极少量的修改,就能和实际系统的主控板进行通讯联测,工作效率的提升自不待言。

再后来,哥在Nortel的时候知道了TIPC协议,好象是E///和IBM捣腾出来的东西。思路上,和Wacos SSI很接近。所不同的是,Wacos SSI在消息头里使用了IP地址,而TIPC则是自定义的节点地址,也因此包含了一个额外的节点地址和特定网络间的地址翻译过程。另外一个区别是,Wacos SSI考虑了远程节点间通信和本地通信的差别,只有远程通信时才传递消息实体,而本地则是传递标识(Handle)来快速完成。TIPC则没讲述这个层次的程序设计问题,也因此在工程实践中应用寥寥。

现如今,UT没了,Nortel也没了。特别是UT,十多年过去了,哥特别怀念那段日子,和我的那个团队。无奈,哥就是灾星,跟喜欢的公司相克。很多局外人都说UT不咋的,就一个做小灵通的;可哥的眼里,那的许多软件开发团队,战斗力一点不比Huawei差。就说哥做的网关城域交换机,才十来个人,而huawei是几十人,好几倍啊,最后市场表现还是平分秋色。当然,我还是蛮佩服huawei的,他们的东西真心做的漂亮,维护界面人性化,不像我们的,很多事情要命令行来实现。不过我们也有特点,就是架构做的非常好,以至于客户的需求,总是能很快实现,而且基本上对现有功能是0风险。呵呵,据说气死不少人!

这当中,有三大功臣:

  • Wacos SSI;
  • 状态机;
  • 数据驱动模型。

状态机的代码,已经在昨晚的内存泄漏里的链接里提供了,有兴趣可以下载或是用在喜欢的地方,哥只希望它有更多机会发挥价值。

嗯,Wacos SSI排在第一!是的,Wacos SSI的消息通信让我们的系统变得非常柔性,模块与模块间几乎没有什么复杂的耦合。想想现在那些公司招聘需求里,要求什么多任务多线程编程能力,精通什么信号量和同步技术,哥就想哭,这就是我们的软件水平,时刻准备着处在玩死自己。哥做程序,只考虑CPU有几个线程核,至于系统有几个进程线程,都是这个决定的,而且合并拆解任务,都是分分钟能改代码实现的事。跟哥一起做软件,就只要记住几点:无论你和谁通信,你只要知道他的地址,然后发消息给他就好了;而你也只要看着自己的队列,有消息就干活,没消息就歇着。至于发消息,就一个标准的函数,而消息封装格式,也是统一的。至于系统函数库里提供的什么信号量,管道啥的,千万别尝试在应用里面使用,否则,编译器会用编译错误来告诉你行不通。

有点扯远了,回到正题。

统一消息的定义,包含两个部分,消息标签和消息头,具体如下:

typedef struct _MSG_TAG_TYPE_
{
zAddr_t srcAddr;
zAddr_t dstAddr;
zHandle_t msgHandle;
} PACKED zMsg_t;

typedef struct _MSG_HEAD_TYPE_
{
byte_t sysrsvd[8]; //reserved for adding src & dst addresses on network.
word_t msgLen;
word_t msgId;
dword_t srcInst;
dword_t dstInst;
} PACKED zMsgHdr_t;

typedef struct _MSG_HEAD_EX_TYPE_
{
zAddr_t srcAddr;
zAddr_t dstAddr;
word_t msgLen;
word_t msgId;
dword_t srcInst;
dword_t dstInst;
byte_t msgBuf[1];
} PACKED zMsgHdrEx_t;

zMsg_t结构是消息标签,应用程序收、发消息时,都是收发的这个数据结构,如下:
int zMsgSend(zMsg_t *msg);
通常来说,我们应该把这个消息标签做的比较小,因为做的太大,来回复制它的内容是需要耗费CPU时间的。比如,你可以将zAddr_t定义成word,zHandle_t定义成dword,这样只需要8字节就够了。不过记得字节对齐,一般来说,要保证长度是4的倍数。

消息头就是消息内容的头部格式段,除了这个头部,剩下的就是应用自定义的payload部分。zMsgHdr_t和zMsgHdrEx_t实质上是一样的。这里面的地址部分,不是必须的,只有当消息透过网络或是总线传递时,才是必须的,否则没法由边界模块还原。而对于应用,如无特别约定,那几个字节是无意义且内容不确定的。

消息标签和消息间是通过msgHandle关联。这样,当消息在本地传递时,msgHandle指向的是一块普通内存;而当消息在本地进程间通信时,则指向共享内存;至于网络或是某个总线传递,边界模块负责本地内存数据和网络数据间的转换。如此一来,最大程度的减少实际消息体的拷贝开销,让消息传递变得高效,且细节处理对应用透明。

Wacos SSI的地址部分,填的是IP地址;当然,它还定义了一个模块号来配合这个地址使用。整个通信过程很简单,应用只需要申请一个队列,并告知SSI,这个队列和哪个目的模块号使用。正常情况下,这个做法都能满足需求,但碰上程序模块重新规划或是特俗测试目的,就有点力不从心了。因此,哥在zMsg_t标签里彻底放弃了IP+module的地址组成,改为TIPC的地址方式。不过这也就让系统必须维护一个路由表,用来完成特定目的地址到队列的映射。

统一消息路由表定义如下:

typedef struct Z_UDP_ADDR_TYPE
{
dword_t ip;
word_t port;
} zUDPAddr_t;
typedef struct Z_MSGQ_ADDR_TYPE
{
void *qid;
} zQueAddr_t;

typedef struct Z_MSGQ_OUT_TYPE
{
zAddr_t addr;
zUDPAddr_t udpAddr;
zQueAddr_t queAddr;
} zMsgRoute_t;

路由表项里首先是地址,对应的是消息的目的地址。接下来是网络地址和队列地址,可以有一个或是都有。

  • 仅队列地址:说明是本地(或者是需要经隐形边界代理转发)的消息,目的地址为队列所有者;
  • 仅网络地址:说明是远程消息,且应该直接网络发送,无需经过边界代理,目的地址为远端模块地址;
  • 含两类地址:远程消息,应用发送时通过队列地址送入边界模块,再通过网络地址发送,,目的地址为远端模块地址。

总上面的关系可以看出,队列和地址间的关系是一对多的关系,即多个地址的消息可能被投送到同一个队列。这就让模块合并变得异常容易,当然,不安规则出牌的模块什么时候什么方法都白搭。通常来说,如果有IP网络的通信要求,系统就需要创建一个基础的网络边界模块。这个模块本身可能并不需要地址,而只需要提供一个消息聚合的队列。当然,在一个开放的网络环境下,这个边界模块可能还需要做些安全性的工作,比如过滤非法消息等,这可以通过在模块内额外配置源IP地址,端口或是源目的地址等实现。如果远端并不支持zMsg_t工作,则这时候的边界模块就需要做好消息的翻译过程,为远端模块分配映射模块地址。当然,这些都是本地的,不属于路由表内容。

从地址映射到真实的目的队列或是网络地址,是个频繁的操作,设计上必须要非常高效。对于地址非常少的系统,比如总共才七八个模块,可以用一个紧凑的数据来做,简单且不妨碍效率。但对于有数十或是上百个地址的系统来说,遍历方法就不可取了。这时应该用二分搜索,或是平衡二叉树。比如城域交换机,有十来块子功能卡,每张卡上有十来个模块,整个系统的地址空间有一百多,采用二分搜索,最多8次就够了!相比消息处理函数的指令数,这部分开销完全可以接受。而从另一个角度来说,统一消息让程序变得简单可控,系统内减少了消息的拷贝操作,所带来的系统效率和性能提升,远远大于查询路由表的开销。

当嵌入式世界有了统一消息后,哪些多线程的开发技巧还有很大价值么?一般应用开发者真的需要理解这些知识么?

时间: 2024-10-12 03:32:51

标准化模块接口--统一消息的相关文章

具体解释EBS接口开发之WIP模块接口

整体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对採用并发请求方式和调用API方式分别进行介绍 内容 WIP模块经常使用标准表简单介绍 WIP事物处理组成 WIP相关业务流程 WIP相关API研究事例 (十)參考文档(七)採购相关的一些知识 (一)WIP模块经常使用标准表简单介绍 1.1   经常使用标准表 例如以下表中列出了与WIP导入相关的表和说明: 表名 说明 其它信息 BOM_STRUCTURES_B BOM头信息 BOM_COMPONENTS_B BOM组件信息

详解EBS接口开发之WIP模块接口

总体说明 文档目的 本文档针对WIP模块业务功能和接口进行分析和研究,对采用并发请求方式和调用API方式分别进行介绍 内容 WIP模块常用标准表简介 WIP事物处理组成 WIP相关业务流程 WIP相关API研究事例 (十)参考文档(七)采购相关的一些知识 (一)WIP模块常用标准表简介 1.1   常用标准表 如下表中列出了与WIP导入相关的表和说明: 表名 说明 其他信息 BOM_STRUCTURES_B BOM头信息 BOM_COMPONENTS_B BOM组件信息 BOM_OPERATIO

Java接口统一样式返回模板

Java接口统一样式返回模板 背景 在进行接口开发时,一般需要一个固定的返回样式,成功和失败的时候,都按照这种格式来进行统一的返回,这样,在与其他人进行接口之间的联调时不会显得很杂乱无章.而这种固定的格式如果放在Java的每个接口单独处理时,又会在接口开发时很繁琐,所以这个时候可以采用封装一个实体类,统一返回固定模板格式的内容. 封装模板 先看一下没有封装之前,接口代码和返回格式: /** * 用户修改 * @return 返回修改的用户信息 */ @PutMapping(value = "up

Node.js中的模块接口module.exports浅析

在写node.js代码时,我们经常需要自己写模块(module).同时还需要在模块最后写好模块接口,声明这个模块对外暴露什么内容.实际上,node.js的模块接口有多种不同写法.这里作者对此做了个简单的总结. 返回一个JSON Object 如下代码是一个简单的示例. 1 var exp = { 2 "version": "1.0.0", 3 "function1": null, 4 "module1": null, 5 };

java微信接口之五—消息分组群发

一.微信消息分组群发接口简介 1.请求:该请求是使用post提交地址为: https://api.weixin.qq.com/cgi-bin/message/mass/sendall?access_token=ACCESS_TOKEN   其中ACCESS_TOKEN是我们动态获取的.   发送的数据:(这里使用图文消息示例) { "filter":{ "group_id":"2" }, "mpnews":{ "me

接口统一管理设想

* 现存的问题* 统一管理实现方案* 例子展示 ##现存的问题## * 趋势要求    >公司逐渐在往SOA架构上靠近,各个系统相互协作,接口服务层出不穷,随之产生的就是,接口安全.协议.文档.维护.升级.监控等问题. * 接口书写不规范,见缝插针    >现在每个项目里面,都有自己对外提供的接口,接口写的位置各不一样,而且注释.文档都不具备,所以除了接口人本身,没有人知道接口在哪里及实现的原理,调用及返回的协议,参数的规范等, 所以就形成了一个单点. * 接口文档形同虚设    >接口

光模块接口类型大盘点

今天来讲一讲光模块接口类型 光模块是可以发射和接收模拟信号的光学器件.电信号通过光模块的发射端后转化为光信号,再经过接收端将光信号转化为电信号以此实现光电转换. 要想让他们实现信息交换,需要将两个光模块连接起来,那么则需要与之匹配的接口. 如下图所示,1个40G QSFP光模块与4个10G SFP光模块相连,需要用MPO-4DLC光纤跳线连接. 接口类型 主要介绍光模块MPO接口.双芯LC接口.单芯LC.和RJ-45接口. MPO接口光模块 MPO接口光模块中有QSFP28光模块.CFP2光模块

使用WeCloud消息推送接口发送消息NodeJs版

WeCloud是一家初创公司的产品,目前主要在做Android和IOS消息推送这块.他们提供了用于向设备发送消息的协议,具体协议内容见消息推送协议. 这篇文章将使用NodeJs基于这个推送协议完成向App用户推送消息的服务端SDK. 首先你需要注册一个帐号,然后系统会为你自动生成一个测试demo,你可以通过扫二维码或先下载到电脑的方式获得apk文件,再将其安装到自己的手机上之后就可以测试发送效果了,每个应用都会有对应的Appkey和Master Secret这两个属性,它是作为发送消息的凭证而存

资深程序员教你用Python如何调企业微信接口发送消息!叼的不行!

进入正题 先来几张好玩的图片 首先进入python交互界面,导入我自己写的模块,然后发一个测试消 息,"Hello,小伙伴们好!",然后看看企业号能否收到相应的消息. 那么问题来了,既然可以这么玩,那岂不可以把所有能通知的信息都可以通过python调用接口发送信息了?那当然了,可以把自己感兴趣的用爬虫爬下来,然后发给自己,也可以用于报警等信息,还可以......就看你自己怎么玩吧 上图第一行嘛,就是python解释器的绝对路径,也就是你python的安装路径,自行修改即可.第二行申明编