本发明涉及计算机技术领域,特别地涉及一种多进程的命令行实现方法。
背景技术:
命令行通常是由用户输入字符串,命令树是将命令行字符串以树形结构存储起来的一种数据结构,命令树的各个分叉,就是命令行节点,命令行原型是挂在各个节点下的。对命令行进行解析就是根据字符串进行匹配,以此来感知用户的意图。
作为一种重要的人机交互方式,命令行输入可提供通过终端操作来进行配置设备的基础功能。然而,为了适配不同的产品特性,往往希望将命令行做成多进程形式,通过使用命令行调用的方式来实现多进程的命令安装、解析、执行、回显、保存、多终端连接等操作,以此达到低耦合,增加模块和进程的可裁剪性的目的。
技术实现要素:
本发明要解决的技术问题是提供一种多进程的命令行实现方法,避免了所有信息通信都采用采用api通信时造成的通道堵塞,提高通信效率。
为此,本发明提供一种多进程的命令行实现方法,所述多进程包括主进程和多个子进程,所述方法包括:对主进程和各子进程进行初始化;在主进程和各子进程之间建立用于配置信息和命令行下发的专用通信通道;主进程根据配置文件通过所述专用通信通道向子进程发起配置加载过程,以及将接收到的命令行通过所述专用通信通道下发至子进程。
进一步地,只对当前需要使用命令行的子进程进行初始化。
更进一步地,通过以下方式判断子进程当前是否需要使用命令行:
预先设置特定的宏集合,用于存储各子进程的命令行裁剪宏的当前使能状态,所述各子进程命令行的裁剪宏使能状态预先以逻辑位或的关系进行存储;
判断当前子进程对应的命令行裁剪宏当前为使能状态时,确定当前子进程需要进行初始化。
进一步地,主进程根据配置文件向子进程发起配置加载过程包括:
在配置文件中预先对只属于某一个子进程的配置加载模式标识为该子进程私有模式,否则,将配置设置模式标识设置为共有模式;
当判断配置文件中的配置加载模式标识为私有模式时,将配置信息发送到对应的子进程,对应的子进程读取其中的配置信息执行配置加载,并同步回应执行结果;
当判断配置文件中的配置加载标识为共有模式时,继续判断该配置文件属于哪些进程,将该配置信息发送到对应的若干个子进程,对应的若干个子进程分别读取其中的配置信息执行配置加载,并同步回应执行结果。
进一步地,在主进程和各子进程之间建立用于配置信息下发的专用通信通道具体为:
主进程作为客户端与作为服务端的各个子进程分别建立套接字连接,连接成功建立专用通信通道。
更进一步地,所述建立套接字连接包括:子进程在创建进程通信套接字时,按照所允许连接的最大终端数量建立(最大终端数+1)个套接字文件描述符;所述套接字文件的文件命名为:文件名加后缀,所述后缀为(最大终端数+1);所述专用通信通道的通道号为:(最大终端数+1)。
进一步地,所述方法还包括:
所述子进程在判断所述主进程初始化完成后,将已经在本地注册安装的所有命令的注册安装数据通过api通道逐一发送给所述主进程;
所述主进程将接收到的各子进程的命令注册安装数据后在本地进行注册命令的首次安装。
其中,所述子进程通过以下方式判断所述主进程初始化完成:
所述子进程在接收到所述主进程在初始化完成后发送的第一信号量时,确定所述主进程初始化完成。
其中,所述方法还包括:所述主进程完成所有子进程命令的首次注册安装后,对所有的命令按照在相同节点下注册地址的大小进行二次安装。
其中,所述主进程完成所有子进程命令的首次注册安装是通过以下方式确定:
预先设置进程部署表,所述进程部署表中包括:需要使用命令行的所有子进程的进程号和这些子进程注册完成标识的对应关系;
当一个子进程的命令在主进程首次注册安装完成时,根据所述命令注册信息所包含的进程号,在进程部署表中将该子进程的注册完成标识置为完成状态;
当所述进程部署表中需要支持命令行的子进程对应的注册完成标识全部被置为完成状态时,表明完成所有子进程命令的首次注册安装。
进一步地,所述方法还包括:在主进程创建所有终端的控制任务之后,主进程通过所述的专用通信通道将接收到的命令行下发至子进程。
更进一步地,主进程判断接收到的命令已经注册后,通过所述的专用通信通道将接收到的命令行下发至子进程。
更进一步地,所述子进程接收到命令行后,由控制台线程任务读取所述命令并进行处理。
其中,主进程通过以下方式判断接收到的命令已经注册:
当主进程接收到通过终端输入命令行时,通过匹配查找自己的命令树找到此命令,表明所述接收到的命令已经注册。
其中,通过以下方法将命令行下发的对应子进程:
主进程根据所述命令属性中的进程号确定该命令属于哪个子进程,并根据该命令的进程号在部署进程表中来查找该终端对应的子进程的套接字文件描述符,确定专用通信通道号,并由此下发至对应的子进程;
所述进程部署表中还包括:每个子进程的进程号和建立通信的套接字文件描述符的对应关系。
其中,主进程创建所有终端的控制任务具体为:
主进程根据所允许连接的最大终端数量创建每一个控制台的线程任务;
为每一个控制台结构分配共享内存。
与现有技术相比,本发明所提出的一种多进程的命令行实现方法存在如下显著优点:
(1)本发明的实施例中,通过专用通信通道下发配置信息和命令行信息,避免了所有信息通信都采用采用api通信时造成的通道堵塞,可以更加高效地完成配置加载过程和命令行下发过程;
(2)在本发明的实施例中,配置加载过程采用私有模式识别,避免将每个配置信息都逐条下发到对应的进程中,减少了进程间的通信频率,使得产品更加稳定;
(3)本发明实施例中,子进程判断主进程完成初始化后进行命令注册数据上报,可以保证主进程收集各子进程的命令安装数据是在一个理想的可靠状态下进行的;
(4)本发明实施例中,在主进程初始化时一次性将支持终端的最大数量的控制台结构创建出来,相对于当有连接时再创建控制台结构能够增加系统的稳定性,减少内存创见释放过程。
附图说明
图1为本发明实施例所提出的多进程的命令行实现方法的总体设计框图;
图2为本发明实施例的专用通信通道的建立示意图;
图3为本发明实施例中的多终端和多线程的对应关系示意图;
图4为本发明实施例中的命令执行过程的示意图。
具体实施方式
为使本发明的目的、技术方案和优点更加清楚明白,下文中将结合附图对本发明的实施例进行详细说明。需要说明的是,在不冲突的情况下,本申请中的实施例及实施例中的特征可以相互任意组合。
在附图的流程图示出的步骤可以在诸如一组计算机可执行指令的计算机系统中执行。并且,虽然在流程图中示出了逻辑顺序,但是在某些情况下,可以以不同于此处的顺序执行所示出或描述的步骤。
以下参考图1所示的总体设计框图,对本发明实施例所提出的一种多进程的命令行实现方法进行详细说明,其中,多进程包括:主进程和仅示出为子进程a,子进程b的多个子进程,此处,对于子进程而言,其数量由本领域普通技术人员根据系统设计需要确定,此处并不做出数量限制,但每个不同的子进程具有不同的进程号。
本发明的实施例所提出的一种多进程的命令行实现方法,包括:
步骤1000:在主进程和各子进程启动时,分别对全局资源进行初始化。
具体地:
在主进程,初始化全局资源是为了对于各子进程所需要的命令行资源进行分配,包括:注册安装主进程命令的节点模式,创建命令树,创建互斥信号量,创建及初始化api(applicationprogramminginterface,应用程序编程接口)等;其中,主进程命令的节点模式主要为公共模式;命令树是命令行字符串被安装存储的树形数据结构;互斥信号量用来保护各子进程将命令发送到主进程后,保证共有资源不被同时访问;api用于建立各子进程将自己的命令注册信息发往主进程的api通道。
在子进程:每个子进程在自己的进程内初始化全局资源,包括:注册安装该子进程命令的共有节点模式,创建命令子树,创建互斥信号量,创建用于命令注册信息的数据缓存线性链表,分配共享控制结构,创建配置加载的内存池等。
对于各子进程进行初始化的步骤需要说明的是:由于产品不同,所需要的配置不同,子进程也不同,有些子进程并不需要使用命令行,由此也就不需要对这些子进程进行全局资源初始化,仅仅是在当前子进程需要使用命令行时才进行初始化,具体地,如何判断当前子进程是否需要进行初始化可以通过如下方式:
预先设置特定的宏集合,用于存储各子进程命令行的裁剪宏使能状态;所述各子进程命令行的裁剪宏使能状态预先以逻辑位或的关系进行存储,即:以0或1来标识是否使能;
判断所述宏集合中该子进程命令行对应的裁剪宏使能状态来确定该子进程是否需要进行初始化,具体的,所述宏集合中该子进程命令行对应的裁剪宏为使能状态则表明需要对该子进程进行初始化,否则,该子进程并不需要进行初始化。
步骤1001:记录进程部署表信息;
所述进程部署表是包括主进程、子进程在内的每个进程各自维护的一个数据结构,包含了所有子进程的信息,具体地包括:每个进程的进程号、进程名称、进程标志、建立通信的套接字文件描述符、命令行通信通道的文件路径和文件名、命令行任务的任务名、子进程注册完成标识等,其中,每个子进程的进程号、进程名称、命令行通信通道的文件路径和文件名以及各子进程命令行任务的任务名是通过预先设置静态定义的,其余信息的初始状态可以为空,动态更新。
所述进程部署表位于共享内存中,其内的信息可由主进程和各子进程读取和写入。
步骤1002:在子进程创建所有终端控制台的线程任务;
在本步骤中,根据预先设置的系统所支持的最大终端数设置对应数量的控制台结构,并分别为各控制台结构创建线程任务,用于接收主进程发送的数据和执行命令,进一步地为了实现配置加载任务,还创建一个线程任务,即:在子进程侧所创建的线程任务数为:最大终端数+1;例如,所设计支持的最大终端数为21个,对应的设置21个控制台结构,并对于21个控制台结构分别创建线程任务,进一步地为了配置加载,还设置有一个控制台结构即对应的建立一个线程任务,此时全部创建的线程任务数为:21+1==22个。
步骤1003:主进程和各子进程之间建立专用通信通道,用于配置加载过程;
在此步骤中,主进程作为所有子进程的一个客户端建立连接;此时,子进程已经创建了所有终端控制台的线程任务,并且对于每个子进程和通信套接字作为服务端,之后主进程作为客户端连接作为服务端的各子进程,连接成功则建立专用通信通道。
由于在创建客户端和服务端时,每个进程都会各自维护一个套接字文件,并且各自创建出各自的套接字文件描述符,这些信息会在一个进程部署表的套接字文件描述符数组中被维护。
在主进程建立专用通道之后,主进程单独维护一个用于配置加载的控制台结构,所述控制台结构的id为(最大终端数+1),且该控制台对应的专用通信通道的通道号fd也是(最大终端数+1)。由此,主进程维护的是控制台的线程任务为终端接口(例如,console口和远程连接口telnet口和ssh口),而子进程除了维护终端接口的控制台任务外还存在一个用于配置加载的控制台线程任务。示例性的说明参考图2所示。
由于命令行可以支持多种连接形态的终端,其连接数也是在系统设计时根据具体场景确定,例如,可以支持1个串口,10个telnet口、10个ssh口,由此在本步骤中对于每一个子进程,在创建进程通信套接字时,按照所允许连接的终端数量建立不同数量终端的套接字文件描述符,文件命名可以为:文件名加后缀,此处的后缀为(最大终端数+1),由此也可以看出:套接字文件是一个元素个数为(最大终端数+1)的数组,可用于主进程和子进程之间的通信,并且依据套接字所建立的通信,子进程为服务端,主进程为客户端,其中文件名由进程部署表对应可知,而所创建的套接字文件描述符需要更新至进程部署表中,可以为与进程号对应的一个数组;例如,在支持不同连接的21的终端时,将为每个子进程建立22个不同终端的文件描述符,文件命名中后缀为0~21,其中0~20用于与每一个终端对应,而21用于对应配置加载;由此,实现了每一个终端对应一个子进程的文件描述符来进行通信,完全避免了各个连接之间的互相影响;。
至此,在完成专用通信通道建立后,可以启动每个控制台线程任务可以来监控主进程发来的数据。
步骤1004:各子进程将自己的所有命令进行注册安装,并在判断主进程已经完成初始化后通过api通道将所有命令对应的注册安装信息逐一发往主进程,由主进程在本地完成各子进程命令的首次注册安装;
在本步骤中,各子进程将自己的所有命令进行安装具体为:每个子进程注册安装命令时首先将每一个命令注册信息结构存入到本子进程内的数据缓存线性链表中,然后在自己的子进程命令子树上进行注册安装,多进程命令注册信息包含一个自己的进程号作为识别命令进程所属的依据,由此完成一个命令的注册安装;并且每个子进程中所有命令依次进行注册安装;此处所述的注册安装指的是:在本子进程所维护的命令子树上进行安装;进一步地,子进程的注册安装命令从数据缓存线性链表中获取后,在数据缓存线性链表中删除相关信息;
在本步骤中,各子进程在判断主进程已经初始化完成可以是通过子进程开始进行初始化后预设的时长确定,但是较佳的可以采用下述方式:
所述主进程在完成初始化之后向各子进程发送第一信号量,以通知各子进程所述主进程已经完成初始化,各子进程可以向所述主进程发送包括进程号的命令注册信息;
各子进程在接收到所述主进程发送的第一信号量之后,才将命令注册信息发往主进程,否则,子进程一直处于阻塞等待状态;由此避免了由于主进程未完成初始化致使多进程注册时可能出现的某个或者某些子进程注册进程可能无法向主进程注册,甚至发生程序崩溃的情况;也就是说,由此保证主进程收集各子进程的命令安装数据是在一个理想的可靠状态下进行。
在本步骤中,各子进程的注册命令是按照接收到的先后顺序依次安装的;
在本步骤中,判断是否完成所有子进程的命令注册安装是通过以下方式:
在一个子进程的命令注册安装在本地安装完成时,根据所述命令注册信息所包含的进程信息,在进程部署表中将该子进程的命令完成标识置为完成状态;
当所述进程部署表中需要支持命令行的子进程对应的完成标识全部被置为完成状态时,表明完成所有子进程的注册命令安装数据。
步骤1005:主进程对所有的命令按照在相同节点下注册地址的大小进行二次安装,以此将所有的命令进行排序安装,避免空间碎片;
步骤1006:主进程根据配置文件通过所建立的专用通信通道向子进程发起配置加载过程,由子进程执行配置加载,将用户配置信息逐条下发到设备中。
由于配置加载是一个多进程模式,属于某一个子进程的配置信息将通过哪个子进程执行配置下发。
具体的,主进程发起配置信息下发,子进程执行配置加载可以采用如下方式:
主进程按照配置文件对应的配置读取命令读取配置信息,当判断该命令是其它子进程的命令时,通过多进程通信通道发送到对应的子进程中,子进程根据注册的回调函数来执行配置加载函数,进而读取其中的命令下发配置。
但较优地,主进程发起配置下发,子进程执行配置加载可以采用如下方式:
在配置文件中预先对只属于某一个子进程的配置加载模式标识为该子进程私有模式,否则,将配置设置模式标识设置为共有模式;
当判断配置文件中的配置设置标识为私有模式时,将该配置信息通过多进程通信通道发送到对应的子进程,对应的子进程执行注册回调函数来执行配置加载函数,进而读取其中的命令下发配置,然后,同步回应执行结果。此处说明一点:主进程不再对配置信息进行解析处理,而仅处于同步等待过程,而子进程将配置信息下发完成后无论是成功还是失败均会回应执行结果到主进程。
当判断配置文件中的配置加载标识为共有模式时,继续判断该配置文件属于哪些进程,将该配置信息通过多进程通信通道发送到对应的子进程,对应的子进程执行注册回调函数来执行配置加载函数,进而读取其中的命令下发配置,然后,同步回应执行结果。此处说明一点:主进程不再对配置信息进行解析处理,而仅处于同步等待过程,而子进程将配置信息下发完成后无论是成功还是失败均会回应执行结果到主进程。
可见,在上述方法中可以更加高效地完成配置加载过程,避免将每个配置信息都逐条下发到对应的进程中,私有模式下可以减少进程间的通信频率,使得产品更加稳定。
步骤1007,主进程创建所有终端的控制台结构。所述的控制台结构是每一终端对应的数据信息,包括:控制台号、字符输入输出id、屏幕显示字符长度、支付缓冲区、连接超时时间、pty信息等。
在主进程侧根据系统设计时连接终端的最大数量创建(最大终端数+1)个控制台结构,每个控制台对应一个控制台线程任务,每个终端独立对应一个线程任务,每个线程任务内给每个控制台结构分配共享的内存空间;由于每个终端都会对应维护一个控制台,而终端对于主进程和多个子进程而言是共用的,因此一个终端的控制台结构也是共用的,控制台结构内包含这个终端的所有信息,包括:接口、模式、输入输出套接字文件描述符、显示属性、屏幕属性等。为每个控制台结构分配共享的内存空间必然可以使得各个进程可以同步读取数据和改变数据,典型的可以将每一个控制台的内存地址放入全局变量中。示例性的,多终端和多线程的对应关系如图3所示。
当每个终端切换到不同模式时可以修改控制台结构,例如,当前控制台出于配置模式下,当用户输入退出命令后,控制台模式可以修改为配置模式的上一级模式中,每个进程都可以获取到修改后控制台结构信息,增加了多进程命令行的易读性和操作性。当某个终端被关闭时不会销毁对应内存,减少了对内存分配的操作频率。
当有一个终端进行连接时,根据终端id来获取全局变量中对应的终端控制台,例如,对于已存在的终端接口,可以将console口的id设为0,,telnet口的id设为1-10,ssh口的id设为11-20。
示例性的,对于console口的连接可以是默认初始创建的,用户可以直接通过终端输入界面输入字符来操作,其他的控制台任务将会创建成功,并且通过打开系统的dev/ptmx文件来获取master和slave,以用于输入输出,当有一个新的连接建立,将用于数据输入输出的文件描述符和终端联立联系就可以操控设备了。
此处再说明一点:在本发明的实施例中,已和控制台建立的连接可能会存在不同的断开情况,具体如下:
(1)主动断开:
当控制台的不活动时间达到预设值时,强制对应的还不活动的用户退出,并断开与终端的连接,此时对应终端的控制台任务将对一些基本属性进行初始化,等待下次连接;示例性的:如果是console口控制台超时,由于console口控制台和终端默认一直连接,所以会一直运行超时机制,而telnet口或ssh口在没有用户主动建立连接时不需要超时,即如果是telnet口或ssh口并没有连接,那么就不进行超时机制,直到有连接进来后再进行超时连接。另外,当终端都处于超时状态后,console只是强制用户退出了终端登录,telnet口或ssh口还会直接将终端和控制台断开连接;当然还可以通过exit和logout命令可以使用户主动退出控制台登录。
(2)被动断开:
被动断开主要针对的就是终端通过telnet口或ssh口和控制台建立连接,在某种情况下,比如网络断开、主动断开,导致和控制台断开连接,此时终端已经断开了而控制台被动断开。通过监控连接状态,从而来判断终端是否处于断开,如果断开就主动调用控制台关闭接口,从而将控制台关闭。
当控制台断开连接后,控制台任务会清空控制台内已有的终端数据信息,然后对应的控制台任务会重新初始化一下控制数据,保证当新的终端连接时数据为有效数据。
步骤1008,在完成控制台线程任务创建完成后,主进程接收到输入的命令行已经注册时,将该命令通过专用通信通道下发至对应的子进程,由子进程执行。命令执行的示意图参见图4所示。
在本步骤中,主进程接收到的命令已经注册是通过以下方式:
当主进程接收到通过终端输入命令行时,通过匹配查找自己的命令树来找到此命令,如果不匹配则表明该命令还未注册并返回错误信息,如果匹配则表明是已经注册的命令,继续获取相应的命令信息。
在本步骤中,主进程根据如下方式确定该命令下发对应的子进程:
主进程根据这个命令的属性中的进程号确定该命令属于哪子进程,并根据该命令的进程号在部署进程表中来查找该终端是第几终端对应的子进程的第几个套接字文件描述符,由此确定对应的发送专用通信通道进行发送。
在本步骤中,该命令通过通信通道下发至对应的子进程具体的包括:
主进程创建一个包含指示报文类别为普通命令的标识的报文,并通过所对应的专用通信通道的通道号fd发送给对应的子进程;对应进程的控制台线程一直处于等待接收主进程发送过来的报文的状态,在接收到报文后,如果根据其中的报文类别分别进行相应处理后,将执行结果返回至主进程;而主进程在发送完该报文后一直等待对应子进程的执行结束返回应答,才继续往下执行,这个过程也是一个同步过程。其中,判断该接收到的报文是普通命令时,读取命令信息结构,并调用结构内的命令注册回调函数,将结构本身、argc、argv等作为形参来执行参数,由此子进程可以读取到该命令的所有信息。
此处,对于终端显示命令特别说明如下:
显示的属性创建在创建控制台时被创建,在执行显示命令时使用,且终端显示一般地分为console口显示和远程终端显示。
console口使用的是标准的输入输出即标准io,其他终端输入输出显示则是通过打开系统的ptmx来获取一个master和slave,而这些创建后都会得到一个ptyname,把这个ptyname通过多进程打开,每一个进程在显示的时候通过往打开的ptyname的id来写入就可以实现多子进程的输出显示。
各个子进程对于控制台来说属于在后台运行,主进程是在前台运行。所以子进程的输出可以通过打开和主进程的对应终端同一个ptyname来输出,ptyname在控制台结构中记录供多进程读取,而对于输入,由于输入的pty文件描述符在主进程打开,所以终端命令输入监控,键盘输入等都是在主进程中,都需要前台监控字符输入,后台来输出显示,并且根据不同的字符,快捷键做出结束还是继续等相应的反应。
主进程做为控制台的前台,需要对终端输入监控。多进程执行命令是一个同步执行,所以在执行这个命令以后就会等待对应进程执行回应,如果是交互命令,动态显示,分屏显示,那么就会接收到命令内的调用函数的回应事件标识,这个回应事件标识包括,执行成功标识、执行失败、交互命令标识、动态刷新标识、分屏显示标识等。主进程根据回应标识事件来进行相应的前台处理,前台会等待用户输入字符,输入后将字符返回到对应进程中,此时主进程继续同步等待对应进程执行回应。直到这个命令执行结束,主进程继续往下执行。
对应子进程在收到主进程发过来的前台字符后进行相应判断,交互命令会去匹配字符输入,动态刷新会判断是否停止输入,分屏显示会判断是继续输出一行还是多行或者是结束输出。
本领域普通技术人员可以理解,上文中所公开方法中的全部或某些步骤、系统、装置中的功能模块/单元可以被实施为软件、固件、硬件及其适当的组合。在硬件实施方式中,在以上描述中提及的功能模块/单元之间的划分不一定对应于物理组件的划分;例如,一个物理组件可以具有多个功能,或者一个功能或步骤可以由若干物理组件合作执行。某些物理组件或所有物理组件可以被实施为由处理器,如中央处理器、数字信号处理器或微处理器执行的软件,或者被实施为硬件,或者被实施为集成电路,如专用集成电路。这样的软件可以分布在计算机可读介质上,计算机可读介质可以包括计算机存储介质(或非暂时性介质)和通信介质(或暂时性介质)。如本领域普通技术人员公知的,术语计算机存储介质包括在用于存储信息(诸如计算机可读指令、数据结构、程序模块或其他数据)的任何方法或技术中实施的易失性和非易失性、可移除和不可移除介质。计算机存储介质包括但不限于ram、rom、eeprom、闪存或其他存储器技术、cd-rom、数字多功能盘(dvd)或其他光盘存储、磁盒、磁带、磁盘存储或其他磁存储装置、或者可以用于存储期望的信息并且可以被计算机访问的任何其他的介质。此外,本领域普通技术人员公知的是,通信介质通常包含计算机可读指令、数据结构、程序模块或者诸如载波或其他传输机制之类的调制数据信号中的其他数据,并且可包括任何信息递送介质。
需要说明的是,本发明还可有其他多种实施例,在不背离本发明精神及其实质的情况下,熟悉本领域的技术人员可根据本发明作出各种相应的改变和变形,但这些相应的改变和变形都应属于本发明所附的权利要求的保护范围。