邹云峰, 张昕, 李捞扒
(1.国网江苏省电力公司 电力科学研究院,南京 210019;2.河海大学 计算机与信息学院,南京 211100)
软件运行平台是一组软件基础设施,属于系统软件的范畴[],为应用软件的运行提供各种必要的支撑。从系统角度来看,软件运行平台负责管理和协调底层软硬件资源,有效地桥接各种异构环境下的资源调用,增加互操作性,从而充分发挥软硬件资源的计算能力[2]。从应用角度来说,软件运行平台抽象了操作系统底层的细节,封装了系统现有的应用接口函数,为用户提供了上层应用的软件编程模式与简单易用的人机交互界面。随着互联网技术的不断发展,软件平台需要连接并管理网络上功能结构各异、数量众多的软硬件资源,因此,具有协调和整合能力的中间件逐渐演变成为网络环境中典型的软件运行平台[3]。
然而,作为软件平台的中间件存在诸多局限,如它们的运行环境相对封闭、静态与固定,而互联网环境则为开放、动态且多变[3],这就对软件运行平台提出了更高的要求。
在实际应用中,软件运行平台也面临这样的挑战。在一些互联网产品的IT型企业中,随着业务需求的不断拓展,越来越多的与新业务对应的功能需要整合到现有的软件系统架构之中。企业为了节约运营成本,必须考虑如何将原有系统与新系统协同作业,因此基于中间件构建的应用系统如何实现跨异构平台的互操作成为了平台技术研究的重点和难点。目前软件平台类型多样,但没有统一的通信协议,为实现跨平台的互操作,需要解决不同平台间的进程通信问题,这是软件平台开发中所涉及的关键问题之一。
针对这一问题,本文设计了一种具有高效可靠进程间通信机制和可移植性的软件运行平台。其本质是作为消息中间件,用来建立连接、接收和转发消息等,屏蔽了不同操作系统的细节差异,为平台所支撑的上层服务端应用提供可靠的运行环境,从而大大减轻了上层应用的开发复杂度,有效缩短了开发流程,提高工作效率。本文主要从3个方面介绍跨系统软件运行平台的实现技术。首先,建立高效可靠的进程间通信机制;其次,封装系统API函数,提供部分通用的服务和管理程序;最后,编写自动化编译部署脚本,实现平台源代码的定制化编译,并部署到操作系统环境中。
平台分成四个模块,分别是功能区、通信机制、被封装的API库、定制化编译部署。功能区以API库和通信机制为基础,配置文件提供配置参数和全局变量,初始化进程、监控进程、通信进程、交互进程和通用服务实现系统初始化、进程监控、消息接收和转发及定时器等功能;通信机制模块实现进程通信功能;被封装的API库提供统一的上层接口;定制化编译部署用于在不同操作系统上部署本平台。平台框架,如图1所示。
图1 平台框架图
跨平台是软件开发领域一个重要的概念,指应用软件不必依赖于某些特定的操作系统或编译器,也不依赖于特定的硬件环境。它泛指程序语言、软件或硬件设备可以在多种作业系统或不同硬件架构的计算机上运作[4]。它能够快速地移植到各种操作系统平台上,在功能上类似于自适配通信环境(ACE)框架[5-7]的OS适配层。
IPC(Inter-Process Communication,进程间通信)是应用程序中经常涉及的重要问题,进程间的数据交互对于应用软件来说至关重要。不同的操作系统平台IPC机制是有区别的,类UNIX系统(包括Linux)的IPC主要包括管道、信号、消息队列、共享内存、信号量;Windows系统的IPC主要包括文件映射、共享内存、匿名管道、命名管道、邮件槽、剪贴板、动态数据交换(DDE)、套接字Socket[8]。
进程通信主要包括3个方面:进程内线程通信;同主机进程间线程通信;不同主机进程间线程通信。通过对不同操作系统IPC机制的分析,本文选择使用以消息队列、共享内存和Socket为组合的IPC机制。
消息队列机制是在内核中开辟的用于保存消息的链表,并作为一种竞争的共享资源,被有通信需求的多进程公用。消息来源为发送方的进程,队列中已有的消息将由指定进程接收[9]。Windows系统可以运用消息缓冲通信来达到消息队列的功能。
共享内存机制允许两个或多个进程共用指定的存储区,这一段存储区可以被两个或多个进程映射至自身的地址空间中[10],数据不需要在进程间复制,所以这是最快的一种IPC方式,它适用于通信数据量较大的场合。
Socket与一般IPC方式有所不同,它专门用于位于不同主机上的进程间网络通信。网络上的不同程序进行数据交换,一般通过一个双向的通信连接实现,这个双向链路的一端就是一个Socket[11]。Socket的跨平台性比其它IPC机制好得多,不但Linux和类UNIX系统可以使用,Windows系统同样可以使用,同时Socket连接是网络环境下进程间通信必不可少的方式[12-14]。
系统应用程序编程接口API(Application Programming Interface)是由操作系统提供的函数,供应用程序访问特定资源。API的封装方法是在代码的编写过程中,使用条件编译[15]。通常情况下,源程序所有行都会被编译,为了实现跨平台,本文使用#ifdef、#ifndef和#pragma等条件编译指令以操作系统类型作为条件进行编译。通过使用条件编译将不同系统上功能相似的系统API函数统一起来,生成相同的开发接口,从而实现API封装。
功能区以封装的系统API和通信机制为基础,包括配置文件、初始化进程、监控进程、通信进程、交互进程和通用服务。
配置文件是一组.ini文件,用来保存平台相关设置,平台可以依据此文件加载系统所需要的环境设置和文件集合,从而方便程序的移植。
初始化进程用于读取配置并初始化环境,实现上层应用的启动和统计,其流程图,如下图2所示。
图2 初始化进程流程图
监控进程通过两种方法检查上层应用的工作状态:目标应用是否异常结束;向目标应用发送测试消息,若不能及时收到响应,则认为目标应用出现异常。若检测到目标应用出现异常则重启之。
通信进程通过创建子线程实现建立外部连接、接收外部消息、外部消息对内分发、内部消息对外分发功能,包括消息接收子线程和消息发送子线程。
交互进程实现平台与上层应用开发人员的交互功能,包括进程跟踪、调试等功能,用于方便开发人员开发和调试程序。
通用服务主要包括定时器、消息发送与接收及进程信息获取等功能。
编译之前,需要配置操作系统的环境变量等参数,为了简化环境变量的配置过程,本文创建了shell脚本——setenv.sh文件,用来配置编译环境,为makefile自动化编译提供所需的参数或变量,主要步骤如下:
a) 清理工作目录
b) 设置全局环境变量
c) 判断系统类型
d) 根据系统类型设置不同的参数
配置环境变量后,利用make工具将大型的开发项目分解成多个更加容易管理的模块,对于包含众多源文件的应用程序,使用makefile可以简明地理顺各文件之间错综复杂的依赖关系,同时它还可以简化编译过程,实现自动化编译。开发程序通常按照不同的模块,分别存放在不同的目录中,这样需要编写多个makefile文件。本软件平台对多级目录使用makefile时,在总目录和每个子目录下均创建makefile,然后由主目录makefile调用子makefile,编译顺序是由主目录makefile决定的,这样就使编译过程变得清晰直观。
不同操作系统的安装流程略有区别,但总体步骤是一样的:
a) 将源代码复制到环境的工作目录下
b) 进入程序主目录
c) 对shell脚本赋予执行权限
d) 执行setenv脚本,设置环境变量
e) 清空前一次编译生成的文件
f) 编译并安装部署
系统类型:LINUX REDHAT,版本信息:Linux version 2.6.18,编译器版本:gcc 4.1.2 20080704 (Red Hat 4.1.2-48),Make版本:make 3.79。
将源码拷贝至PROJECT_DIR目录下,进入程序主目录,顺序执行以下命令:
chmodu+x*.sh #对shell脚本赋予执行权限
./setenv_64.sh #设置环境变量
make Clean
make Install #编译安装
安装完成后,在$PROJECT_DIR/bin生成可执行程序和脚本,如图3所示。
在PROJECT_DIR/lib生成库文件,如图4所示。
系统类型:HP-UX,版本信息:HP-UX 11.31,Patch版本为高于或等于0803,编译器:aCC 3.5以上,Make版本:make 3.79。
图3 Linux系统环境下生成的可执行程序和脚本
图4 Linux系统环境下生成的库文件
将源码拷贝至$PROJECT_DIR目录下,进入程序主目录,顺序执行以下命令:
chmodu+x*.sh #对shell脚本赋予执行权限
./setenv_64.sh #设置环境变量
make Clean
make Install #编译安装
安装完成后,在$PROJECT_DIR/bin生成可执行程序和脚本,如图5所示。
图5 HP-UX系统环境下生成的可执行程序和脚本
在$PROJECT_DIR/lib生成库文件,如图6所示。
图6 HP-UX系统环境下生成的库文件
本文的主要工作是给出了一个基于跨系统进程间通信的软件运行平台设计方案。它基于跨系统技术实现,利用通用的3种通信机制——消息队列、共享内存和Socket的组合实现消息传递,通过封装系统API,屏蔽了异构操作系统的细节差异,提供统一的访问接口和部分通用的服务与管理程序,通过定制化编译部署方法使之能够适应不同的操作系统,为其支撑的上层应用提供良好的运行环境。