适用于Linux服务器集群的多场景进程间通信方法
文献发布时间:2023-06-19 11:32:36
技术领域
本发明属于进程间通信技术领域,具体涉及一种适用于Linux服务器集群的多场景进程间通信方法。
背景技术
现有通用的Linux进程间通信方式主要包括:信号、无名管道、命名管道、消息队列、共享内存、信号量、socket等。其中,socket支持跨服务器节点进程间通信、其余通信方式只能适用于同一台服务器节点进程间通信。
在实际的软件开发过程中,如果同时存在同一台服务器节点进程间通信和不同服务器节点进程间通信的业务需求时,需要分别使用不同的进程间通信方式,具有实现过程复杂,资源开销大的问题。
发明内容
针对现有技术存在的缺陷,本发明提供一种适用于Linux服务器集群的多场景进程间通信方法,可有效解决上述问题。
本发明采用的技术方案如下:
本发明提供一种适用于Linux服务器集群的多场景进程间通信方法,包括以下步骤:
步骤1,服务器集群包括n个服务器节点NS;每个服务器节点NS均配置messagebus服务模块MB;每个服务器节点NS均运行多个进程;
其中,对于任意的服务器节点NS中运行的需要接收消息的进程,称为消息接收进程,所述消息接收进程在进程启动时,均创建进程通信服务端模块server,所述进程通信服务端模块server为运行于所述消息接收进程中的一个线程;
所述进程通信服务端模块server创建用于与其他进程通信的本地套接字socket;
步骤2,在服务器集群中,当任意的服务器节点NS(A)运行的消息发送进程pro(A),需要与其他的服务器节点NS(B)运行的消息接收进程pro(B)通信时,消息发送进程pro(A)创建进程通信客户端模块client(A),所述进程通信客户端模块client(A)为运行于所述消息发送进程pro(A)中的一个线程;
其中,消息接收进程pro(B)创建的进程通信服务端模块表示为进程通信服务端模块server(B),进程通信服务端模块server(B)创建的用于与其他进程通信的本地套接字表示为本地套接字socket(B);
然后,进程通信客户端模块client(A)创建用于与本地套接字socket(B)通信的本地套接字socket(A);
本地套接字socket(A)的创建方法为:
创建初始的本地套接字socket(A),向本地套接字socket(A)传递参数,传递参数的方式为:
判断目的服务器节点是否与本服务器节点相同,即:判断服务器节点NS(B)是否与服务器节点NS(A)相同,如果不相同,则表明需要进行跨节点进程间通信,因此,向初始的本地套接字socket(A)传入服务器节点的ID,然后,将messagebus服务模块MBus(A)创建的本地套接字socket(C)的套接字文件路径赋值给本地套接字socket(A);
如果相同,则表明需要进行本节点进程间通信,因此,不向初始的本地套接字socket(A)传入服务器节点的ID,然后,将消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径赋值给本地套接字socket(A);
步骤3,进程通信客户端模块client(A)读取本地套接字socket(A),判断本地套接字socket(A)中是否被传入目的服务器节点ID,如果没有,则表明需要进行本节点进程间通信,并执行步骤4;如果有,则表明需要进行跨节点进程间通信,并执行步骤5-步骤11;
步骤4,消息发送进程pro(A)的本地套接字socket(A),与消息接收进程pro(B)的本地套接字socket(B)建立连接,直接通过套接字方式进行通信,并结束流程;
步骤5,消息发送进程pro(A)所在的服务器节点NS(A)创建并运行messagebus服务模块MBus(A),messagebus服务模块MBus(A)为运行于服务器节点NS(A)的一个独立进程;messagebus服务模块MBus(A)创建本地套接字socket(C)和网络套接字socket(D);
消息接收进程pro(B)所在的服务器节点NS(B)创建并运行messagebus服务模块MBus(B),messagebus服务模块MBus(B)为运行于服务器节点NS(B)的一个独立进程;messagebus服务模块MBus(B)创建本地套接字socket(F)和网络套接字socket(E);
步骤6,进程通信客户端模块client(A)的本地套接字socket(A),与messagebus服务模块MBus(A)的本地套接字socket(C)建立通信连接,进而使进程通信客户端模块client(A)和messagebus服务模块MBus(A)建立通信连接;
然后,进程通信客户端模块client(A)向messagebus服务模块MBus(A)发送路由消息;其中,所述路由消息包括消息本体、目的服务器节点ID和消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径;
步骤7,messagebus服务模块MBus(A)实时对路由消息进行监听和更新已存储的仿真路由表;其中,所述仿真路由表,用于存储服务器集群中每个服务器节点的服务器节点ID和服务器节点IP地址之间的映射关系;
当messagebus服务模块MBus(A)监听到步骤6的路由消息时,messagebus服务模块MBus(A)对路由消息进行解析,得到目的服务器节点ID;然后,查找所述仿真路由表,得到目的服务器节点IP地址;
步骤8,messagebus服务模块MBus(A),根据目的服务器节点IP地址,定位到目的服务器节点的messagebus服务模块,即:messagebus服务模块MBus(B);
步骤9,messagebus服务模块MBus(A)的网络套接字socket(D),与messagebus服务模块MBus(B)的网络套接字socket(E)建立网络套接字通信连接,并通过网络套接字通信连接,向messagebus服务模块MBus(B)发送路由消息;其中,所述路由消息包括消息本体和消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径;
步骤10,messagebus服务模块MBus(B)根据消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径,定位到消息接收进程pro(B);
然后,messagebus服务模块MBus(B)的本地套接字socket(F),与消息接收进程pro(B)的本地套接字socket(B)建立通信连接,进而使messagebus服务模块MBus(B)和消息接收进程pro(B)建立通信连接;
步骤11,messagebus服务模块MBus(B)将消息本体发送给消息接收进程pro(B),进而实现消息发送进程pro(A)向消息接收进程pro(B)进行跨节点进程间通信。
优选的,步骤2中,消息发送进程pro(A)创建进程通信客户端模块client(A),具体为:
消息发送进程pro(A)调用进程间通信客户类CxipcClient,对进程间通信客户类CxipcClient进行实例化和初始化操作,得到进程通信客户端模块client(A)。
其中,实例化和初始化方法为:
步骤2.1,进程间通信客户类CxipcClient的构造函数具有两个参数,分别为:destGuid参数和destProName参数;进程间通信客户类CxipcClient具有两个成员变量,分别为m_strDestGuid成员变量和m_strDestServerAddr成员变量;
步骤2.2,如果目的进程,即消息接收进程pro(B)为服务器集群中另一个服务器节点运行的进程,则:
步骤2.2.1,消息发送进程pro(A)向进程间通信客户类CxipcClient的构造函数传递两个参数,具体的,消息发送进程pro(A)向destGuid参数传递目的服务器节点ID,即:服务器节点NS(B)的ID;消息发送进程pro(A)向destProName参数传递目的进程名称,即:消息接收进程pro(B)的名称;
步骤2.2.2,当destGuid参数被传入目的服务器节点ID时,向m_strDestGuid成员变量和m_strDestServerAddr成员变量赋值,赋值方法为:向m_strDestGuid成员变量赋值目的服务器节点ID;向m_strDestServerAddr成员变量赋值本节点messagebus服务模块的套接字文件的文件路径,即:messagebus服务模块MBus(A)创建的本地套接字socket(C)的套接字文件路径,进而构造得到进程通信客户端模块client(A);
步骤2.3,如果消息接收进程pro(B)为服务器节点NS(A)运行的另一个进程,则:
步骤2.3.1,消息发送进程pro(A)向进程间通信客户类CxipcClient的构造函数传递一个参数,具体的,消息发送进程pro(A)向destGuid参数不传递参数;消息发送进程pro(A)向destProName参数传递目的进程名称,即:消息接收进程pro(B)的名称;
步骤2.3.2,当destGuid参数没有被传入参数时,向m_strDestGuid成员变量赋值为空,向m_strDestServerAddr成员变量赋值destProName参数传入的目的进程名称,即:消息接收进程pro(B)的名称,进而构造得到进程通信客户端模块client(A)。
优选的,初始的本地套接字socket(A)的创建方法为:
调用socket创建与消息发送进程pro(A)唯一对应的套接字文件file(A);所述套接字文件file(A)存储的套接字的类型为数据报套接字类型;然后,获得与所述套接字文件file(A)对应的套接字描述符;所述套接字描述符用于访问所述套接字文件file(A);
所述套接字文件file(A)具有sockaddr_un结构体的成员变量sun_path;调用getpid函数得到消息发送进程pro(A)的进程名称以及套接字描述符,将消息发送进程pro(A)的进程名称以及套接字描述符相结合,得到消息发送进程pro(A)的套接字文件file(A)的文件路径,将消息发送进程pro(A)的套接字文件file(A)的文件路径赋值给成员变量sun_path;
成员变量sun_path被赋值后,调用bind为套接字文件file(A)命名,调用setsockopt函数对消息发送和接受的延时时间进行设置,得到设置后的套接字文件file(A),称为套接字文件file"(A),并根据消息发送进程pro(A)的套接字文件file(A)的文件路径,在相应目录下生成套接字文件file"(A),然后,消息发送进程pro(A)采用套接字文件file"(A)进行本地进程间通信。
优选的,步骤6中,进程通信客户端模块client(A)向messagebus服务模块MBus(A)发送路由消息,具体为:
进程通信客户端模块client(A),支持路由消息发送和使用protobuf对消息本体进行序列换和反序列换之后的发送;其中,路由消息发送时,可设置是否接受通信消息回复,如果调用发送函数XipcMsgReq时bool型的reply参数赋值为true,则表明需要接受通信消息回复;如果reply参数赋值为false,则表明不需要接受通信消息回复;
另外,路由消息发送时,采用二次限长发送机制;所述二次限长发送机制是指:消息一次发送的最大长度为65536,当消息长度小于65536个字节时,消息一次发送;当消息长度大于65536个字节时,消息经过多次发送,直至消息被完全发送。
优选的,messagebus服务模块MBus(A)的实现方式为:
1)messagebus服务模块MBus(A)具有三个实现类,分别为:消息处理类、接受消息服务类、发送消息客户类;
2)对消息处理类进行实例化,得到消息处理对象;同时,每当消息处理类实例化时,均下载当前最新的仿真路由表;
消息处理对象在接收到来自于进程通信客户端模块client(A)的路由消息时,对路由消息的消息头结构体进行解析,得到消息头结构体中的msgDestGuid结构体成员变量,即目的服务器节点ID;
然后,消息处理对象查找已下载的当前最新的仿真路由表,得到目的服务器节点IP地址;
3)调用发送消息客户类,对发送消息客户类实例化,得到发送消息对象;
发送消息对象的构造函数调用ConnectServer成员,创建类型为SOCK_STREAM的流式套接字;ConnectServer成员调用setsockopt对流式套接字进行设置,包括:设置流式套接字关闭延时等待、套接字重用、发送和接受消息延时;类型为SOCK_STREAM的流式套接字只绑定一个目的端口,即:目的节点messagebus服务模块监听的端口;
4)对接受消息服务类实例化,得到接受消息服务对象;接受消息服务对象用于接收目的节点messagebus服务模块返回的消息回复;接受消息服务对象接收到消息回复后,读取消息头结构体中的MsgDestProName目的进程名称的结构体成员,进而将消息发送到目的进程。
优选的,4)中,得到接受消息服务对象后,创建一个MsgWaitTsk线程;
其中,MsgWaitTsk线程的创建,采用在接受消息服务类初始化的成员方法中调用等待接受消息任务MsgWaitTsk的成员方法实现;
其中,接受消息服务类初始化的成员方法,内部实现是:调用socket创建流式套接字;调用setsockopt函数设置重用套接字和禁止Nagle算法选项;调用listen函数,设置未完成连接队列的最大长度为1024;创建MsgWaitTsk线程中开启等待消息和转发消息的过程;
MsgWaitTsk线程内部实现是:采用epoll机制实现接受处理消息的高并发处理,调用accept函数获取新的获取连接套接字描述符nRemoteFd;然后,创建发送消息至目的进程的线程OnClientConnectedTsk,线程OnClientConnectedTsk根据连接套接字描述符nRemoteFd调用recv函数,接收消息;
接收到长度正确的消息之后,调用接受消息服务对象的成员函数OnMsgHandle,将接收到的消息发送到MsgDestProName目的进程的服务端模块。
优选的,进程通信服务端模块server(B)创建的用于与其他进程通信的本地套接字表示为本地套接字socket(B),具体为:
进程通信服务端模块server(B)的实现类的构造函数,调用CxipcSocket类中的XipcSocketCreate函数,生成本地套接字socket(B);所述本地套接字socket(B)的类型为数据报套接字SOCK_DGRAM类型;所述本地套接字socket(B)包括sockaddr_un成员变量和sun_path成员变量;
对sockaddr_un成员变量和sun_path成员变量赋值,赋值方法为:将消息接收进程pro(B)的变量名称赋值给sun_path成员变量;将消息接收进程pro(B)路径名称赋值给sockaddr_un成员变量;对sockaddr_un成员变量和sun_path成员变量赋值后,在内存执行的路径下生成与消息接收进程pro(B)对应的套接字文件。
优选的,消息接收进程pro(B)创建进程通信服务端模块server(B)和本地套接字socket(B)后,进程通信服务端模块server(B)创建接收消息等待线程MsgRecvTsk,用于接受进程通信客户端模块发送的消息;
其中,接收消息等待线程MsgRecvTsk的内部实现是:
调用XipcSockNeedRead对套接字描述符和延时时间进行判断;方式为:
XipcSockNeedRead调用select对套接字描述符进行判断,执行select后,如果select返回值大于0,XipcSockNeedRead函数返回0,此时调用recvfrom函数接受消息;recvfrom函数接受消息后,执行OnMsgHandle函数,将数据传输到MsgDestProName目的进程的进程通信服务端模块server(B);
进程通信服务端模块server(B)利用protubuf对接收到的数据进行反序列化操作,得到消息本体。
优选的,执行OnMsgHandle函数,具体为:
OnMsgHandle函数内部实现是调用传递消息的类Cclient,执行传递消息的类Cclient的添加数据的成员方法AddMsgData获取数据后,把传递消息的类Cclient加入Cclient的list的容器内;
进程通信服务端模块server(B)从Cclient的list的容器内部提取得到数据;
如果需要消息回复,进程通信服务端模块server(B)调用XipcAckMsg成员变量对来自进程通信客户端模块client(A)的消息进行回复。
本发明提供的一种适用于Linux服务器集群的多场景进程间通信方法具有以下优点:
本发明提供的适用于Linux服务器集群的多场景进程间通信方法,使不同场景下的进程通信的操作变得简便快捷,本服务器节点进程通信和跨服务器节点进程通信的函数调用采用相同的函数实现,函数调用十分简单易用。利用仿真路由查询的方式消除服务器集群中增加服务器或修改服务器IP地址对服务器之间进程通信的影响。
附图说明
图1为本发明提供的适用于Linux服务器集群的多场景进程间通信方法的详细流程示意图;
图2为本发明提供的适用于Linux服务器集群的多场景进程间通信方法的流程示意图;
图3为本发明提供的messagebus服务模块MBus(A)消息处理流程图;
图4为本发明提供的messagebus服务模块MBus(B)消息处理流程图。
具体实施方式
为了使本发明所解决的技术问题、技术方案及有益效果更加清楚明白,以下结合附图及实施例,对本发明进行进一步详细说明。应当理解,此处所描述的具体实施例仅用以解释本发明,并不用于限定本发明。
服务器集群内部在跨服务器节点使用socket进行进程间通信的过程中,是直接通过服务器的IP地址和绑定端口进行进程间通信的。此种方式存在以下问题:当服务器集群中某一台服务器IP地址更改后,会对集群服务器的进程通信造成很大的影响,且需要进行进程通信的进程服务均需要占用一个或多个端口,具有资源浪费的问题。
具体的,本发明属于Linux操作系统的进程间通信的软件技术,具体涉及适用于Linux服务器集群的多场景进程通信方式,本发明解决服务器集群内部在同一服务器节点和不同服务器节点进程间通信时,使用多种进程通信方式的操作弊端。该发明在处理不同场景的服务器进程间通信时,只调用一种进程间通信的实现方式,根据进程通信调用统一函数的传参,进而进行跨服务器节点进程间或者本地服务器节点进程间通信过程。以自建仿真路由表的形式,利用服务器ID经过进程通信messagebus服务模块查询仿真路由表得到服务器的IP地址后,并由messagebus服务模块转发消息。此方式消除了服务器更改IP地址后对跨节点进程通信的影响,减少了进程服务对端口的占用。
参考图1-图4,本发明提供一种适用于Linux服务器集群的多场景进程间通信方法,可通过C++语言实现,功能实现硬件条件:Linux操作系统服务器通用。包括以下步骤:
步骤1,服务器集群包括n个服务器节点NS;每个服务器节点NS均配置messagebus服务模块MB;每个服务器节点NS均运行多个进程;
其中,对于任意的服务器节点NS中运行的需要接收消息的进程,称为消息接收进程,所述消息接收进程在进程启动时,均创建进程通信服务端模块server,所述进程通信服务端模块server为运行于所述消息接收进程中的一个线程;
所述进程通信服务端模块server创建用于与其他进程通信的本地套接字socket;
步骤2,在服务器集群中,当任意的服务器节点NS(A)运行的消息发送进程pro(A),需要与其他的服务器节点NS(B)运行的消息接收进程pro(B)通信时,消息发送进程pro(A)创建进程通信客户端模块client(A),所述进程通信客户端模块client(A)为运行于所述消息发送进程pro(A)中的一个线程;
其中,消息接收进程pro(B)创建的进程通信服务端模块表示为进程通信服务端模块server(B),进程通信服务端模块server(B)创建的用于与其他进程通信的本地套接字表示为本地套接字socket(B);进程通信服务端模块server(B)创建的用于与其他进程通信的本地套接字表示为本地套接字socket(B),具体为:
进程通信服务端模块server(B)的实现类的构造函数,调用CxipcSocket类中的XipcSocketCreate函数,生成本地套接字socket(B);所述本地套接字socket(B)的类型为数据报套接字SOCK_DGRAM类型;所述本地套接字socket(B)包括sockaddr_un成员变量和sun_path成员变量;
对sockaddr_un成员变量和sun_path成员变量赋值,赋值方法为:将消息接收进程pro(B)的变量名称赋值给sun_path成员变量;将消息接收进程pro(B)路径名称赋值给sockaddr_un成员变量;对sockaddr_un成员变量和sun_path成员变量赋值后,在内存执行的路径下生成与消息接收进程pro(B)对应的套接字文件。
然后,进程通信客户端模块client(A)创建用于与本地套接字socket(B)通信的本地套接字socket(A);
本地套接字socket(A)的创建方法为:
创建初始的本地套接字socket(A);初始的本地套接字socket(A)的创建方法为:调用socket创建与消息发送进程pro(A)唯一对应的套接字文件file(A);所述套接字文件file(A)存储的套接字的类型为数据报套接字类型;然后,获得与所述套接字文件file(A)对应的套接字描述符;所述套接字描述符用于访问所述套接字文件file(A);
所述套接字文件file(A)具有sockaddr_un结构体的成员变量sun_path;调用getpid函数得到消息发送进程pro(A)的进程名称以及套接字描述符,将消息发送进程pro(A)的进程名称以及套接字描述符相结合,得到消息发送进程pro(A)的套接字文件file(A)的文件路径,将消息发送进程pro(A)的套接字文件file(A)的文件路径赋值给成员变量sun_path;
成员变量sun_path被赋值后,调用bind为套接字文件file(A)命名,调用setsockopt函数对消息发送和接受的延时时间进行设置,得到设置后的套接字文件file(A),称为套接字文件file"(A),并根据消息发送进程pro(A)的套接字文件file(A)的文件路径,在相应目录下生成套接字文件file"(A),然后,消息发送进程pro(A)采用套接字文件file"(A)进行本地进程间通信。
另外,消息接收进程pro(B)创建进程通信服务端模块server(B)和本地套接字socket(B)后,进程通信服务端模块server(B)创建接收消息等待线程MsgRecvTsk,用于接受进程通信客户端模块发送的消息;
其中,接收消息等待线程MsgRecvTsk的内部实现是:
调用XipcSockNeedRead对套接字描述符和延时时间进行判断;方式为:
XipcSockNeedRead调用select对套接字描述符进行判断,执行select后,如果select返回值大于0,XipcSockNeedRead函数返回0,此时调用recvfrom函数接受消息;recvfrom函数接受消息后,执行OnMsgHandle函数,将数据传输到MsgDestProName目的进程的进程通信服务端模块server(B);
进程通信服务端模块server(B)利用protubuf对接收到的数据进行反序列化操作,得到消息本体。
其中:执行OnMsgHandle函数,具体为:
OnMsgHandle函数内部实现是调用传递消息的类Cclient,执行传递消息的类Cclient的添加数据的成员方法AddMsgData获取数据后,把传递消息的类Cclient加入Cclient的list的容器内;
进程通信服务端模块server(B)从Cclient的list的容器内部提取得到数据;
如果需要消息回复,进程通信服务端模块server(B)调用XipcAckMsg成员变量对来自进程通信客户端模块client(A)的消息进行回复。
然后,向初始的本地套接字socket(A)传递参数,传递参数的方式为:
判断目的服务器节点是否与本服务器节点相同,即:判断服务器节点NS(B)是否与服务器节点NS(A)相同,如果不相同,则表明需要进行跨节点进程间通信,因此,向初始的本地套接字socket(A)传入服务器节点的ID,然后,将messagebus服务模块MBus(A)创建的本地套接字socket(C)的套接字文件路径赋值给本地套接字socket(A);
如果相同,则表明需要进行本节点进程间通信,因此,不向初始的本地套接字socket(A)传入服务器节点的ID,然后,将消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径赋值给本地套接字socket(A);
本步骤中,消息发送进程pro(A)创建进程通信客户端模块client(A),具体为:
消息发送进程pro(A)调用进程间通信客户类CxipcClient,对进程间通信客户类CxipcClient进行实例化和初始化操作,得到进程通信客户端模块client(A)。
其中,实例化和初始化方法为:
步骤2.1,进程间通信客户类CxipcClient的构造函数具有两个参数,分别为:destGuid参数和destProName参数;进程间通信客户类CxipcClient具有两个成员变量,分别为m_strDestGuid成员变量和m_strDestServerAddr成员变量;
步骤2.2,如果目的进程,即消息接收进程pro(B)为服务器集群中另一个服务器节点运行的进程,则:
步骤2.2.1,消息发送进程pro(A)向进程间通信客户类CxipcClient的构造函数传递两个参数,具体的,消息发送进程pro(A)向destGuid参数传递目的服务器节点ID,即:服务器节点NS(B)的ID;消息发送进程pro(A)向destProName参数传递目的进程名称,即:消息接收进程pro(B)的名称;
步骤2.2.2,当destGuid参数被传入目的服务器节点ID时,向m_strDestGuid成员变量和m_strDestServerAddr成员变量赋值,赋值方法为:向m_strDestGuid成员变量赋值目的服务器节点ID;向m_strDestServerAddr成员变量赋值本节点messagebus服务模块的套接字文件的文件路径,即:messagebus服务模块MBus(A)创建的本地套接字socket(C)的套接字文件路径,进而构造得到进程通信客户端模块client(A);
步骤2.3,如果消息接收进程pro(B)为服务器节点NS(A)运行的另一个进程,则:
步骤2.3.1,消息发送进程pro(A)向进程间通信客户类CxipcClient的构造函数传递一个参数,具体的,消息发送进程pro(A)向destGuid参数不传递参数;消息发送进程pro(A)向destProName参数传递目的进程名称,即:消息接收进程pro(B)的名称;
步骤2.3.2,当destGuid参数没有被传入参数时,向m_strDestGuid成员变量赋值为空,向m_strDestServerAddr成员变量赋值destProName参数传入的目的进程名称,即:消息接收进程pro(B)的名称,进而构造得到进程通信客户端模块client(A)。
步骤3,进程通信客户端模块client(A)读取本地套接字socket(A),判断本地套接字socket(A)中是否被传入目的服务器节点ID,如果没有,则表明需要进行本节点进程间通信,并执行步骤4;如果有,则表明需要进行跨节点进程间通信,并执行步骤5-步骤11;
步骤4,消息发送进程pro(A)的本地套接字socket(A),与消息接收进程pro(B)的本地套接字socket(B)建立连接,直接通过套接字方式进行通信,并结束流程;
步骤5,消息发送进程pro(A)所在的服务器节点NS(A)创建并运行messagebus服务模块MBus(A),messagebus服务模块MBus(A)为运行于服务器节点NS(A)的一个独立进程;messagebus服务模块MBus(A)创建本地套接字socket(C)和网络套接字socket(D);
消息接收进程pro(B)所在的服务器节点NS(B)创建并运行messagebus服务模块MBus(B),messagebus服务模块MBus(B)为运行于服务器节点NS(B)的一个独立进程;messagebus服务模块MBus(B)创建本地套接字socket(F)和网络套接字socket(E);
其中,messagebus服务模块MBus(A)的实现方式为:
1)messagebus服务模块MBus(A)具有三个实现类,分别为:消息处理类、接受消息服务类、发送消息客户类;
2)对消息处理类进行实例化,得到消息处理对象;同时,每当消息处理类实例化时,均下载当前最新的仿真路由表;
消息处理对象在接收到来自于进程通信客户端模块client(A)的路由消息时,对路由消息的消息头结构体进行解析,得到消息头结构体中的msgDestGuid结构体成员变量,即目的服务器节点ID;
然后,消息处理对象查找已下载的当前最新的仿真路由表,得到目的服务器节点IP地址;
3)调用发送消息客户类,对发送消息客户类实例化,得到发送消息对象;
发送消息对象的构造函数调用ConnectServer成员,创建类型为SOCK_STREAM的流式套接字;ConnectServer成员调用setsockopt对流式套接字进行设置,包括:设置流式套接字关闭延时等待、套接字重用、发送和接受消息延时;类型为SOCK_STREAM的流式套接字只绑定一个目的端口,即:目的节点messagebus服务模块监听的端口;
4)对接受消息服务类实例化,得到接受消息服务对象;接受消息服务对象用于接收目的节点messagebus服务模块返回的消息回复;接受消息服务对象接收到消息回复后,读取消息头结构体中的MsgDestProName目的进程名称的结构体成员,进而将消息发送到目的进程。
4)中,得到接受消息服务对象后,创建一个MsgWaitTsk线程;
其中,MsgWaitTsk线程的创建,采用在接受消息服务类初始化的成员方法中调用等待接受消息任务MsgWaitTsk的成员方法实现;
其中,接受消息服务类初始化的成员方法,内部实现是:调用socket创建流式套接字;调用setsockopt函数设置重用套接字和禁止Nagle算法选项;调用listen函数,设置未完成连接队列的最大长度为1024;创建MsgWaitTsk线程中开启等待消息和转发消息的过程;
MsgWaitTsk线程内部实现是:采用epoll机制实现接受处理消息的高并发处理,调用accept函数获取新的获取连接套接字描述符nRemoteFd;然后,创建发送消息至目的进程的线程OnClientConnectedTsk,线程OnClientConnectedTsk根据连接套接字描述符nRemoteFd调用recv函数,接收消息;
接收到长度正确的消息之后,调用接受消息服务对象的成员函数OnMsgHandle,将接收到的消息发送到MsgDestProName目的进程的服务端模块。
步骤6,进程通信客户端模块client(A)的本地套接字socket(A),与messagebus服务模块MBus(A)的本地套接字socket(C)建立通信连接,进而使进程通信客户端模块client(A)和messagebus服务模块MBus(A)建立通信连接;
然后,进程通信客户端模块client(A)向messagebus服务模块MBus(A)发送路由消息;其中,所述路由消息包括消息本体、目的服务器节点ID和消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径;
进程通信客户端模块client(A)向messagebus服务模块MBus(A)发送路由消息,具体为:
进程通信客户端模块client(A),支持路由消息发送和使用protobuf对消息本体进行序列换和反序列换之后的发送;其中,路由消息发送时,可设置是否接受通信消息回复,如果调用发送函数XipcMsgReq时bool型的reply参数赋值为true,则表明需要接受通信消息回复;如果reply参数赋值为false,则表明不需要接受通信消息回复;
另外,路由消息发送时,采用二次限长发送机制;所述二次限长发送机制是指:消息一次发送的最大长度为65536,当消息长度小于65536个字节时,消息一次发送;当消息长度大于65536个字节时,消息经过多次发送,直至消息被完全发送。
步骤7,messagebus服务模块MBus(A)实时对路由消息进行监听和更新已存储的仿真路由表;其中,所述仿真路由表,用于存储服务器集群中每个服务器节点的服务器节点ID和服务器节点IP地址之间的映射关系;
当messagebus服务模块MBus(A)监听到步骤6的路由消息时,messagebus服务模块MBus(A)对路由消息进行解析,得到目的服务器节点ID;然后,查找所述仿真路由表,得到目的服务器节点IP地址;
步骤8,messagebus服务模块MBus(A),根据目的服务器节点IP地址,定位到目的服务器节点的messagebus服务模块,即:messagebus服务模块MBus(B);
步骤9,messagebus服务模块MBus(A)的网络套接字socket(D),与messagebus服务模块MBus(B)的网络套接字socket(E)建立网络套接字通信连接,并通过网络套接字通信连接,向messagebus服务模块MBus(B)发送路由消息;其中,所述路由消息包括消息本体和消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径;
步骤10,messagebus服务模块MBus(B)根据消息接收进程pro(B)的本地套接字socket(B)的套接字文件路径,定位到消息接收进程pro(B);
然后,messagebus服务模块MBus(B)的本地套接字socket(F),与消息接收进程pro(B)的本地套接字socket(B)建立通信连接,进而使messagebus服务模块MBus(B)和消息接收进程pro(B)建立通信连接;
步骤11,messagebus服务模块MBus(B)将消息本体发送给消息接收进程pro(B),进而实现消息发送进程pro(A)向消息接收进程pro(B)进行跨节点进程间通信。
本发明还提供一种适用于Linux服务器集群的多场景进程间通信系统,包括:
进程通信客户端模块client(A):
当任意的服务器节点NS(A)运行的消息发送进程pro(A),需要与其他的服务器节点NS(B)运行的消息接收进程pro(B)通信时,消息发送进程pro(A)创建进程通信客户端模块client(A),进程通信客户端模块client(A)的创建方式为:
消息发送进程pro(A)对进程通信客户端模块client(A)的实现类进行实例化和初始化操作。在实例化时,对进程通信客户端模块client(A)的实现类的构造函数进行参数传递,传参数量为2,分别为destGuid参数和destProName参数。其中,destGuid参数为消息服务端的目的服务器ID(或为空),destProName参数为消息服务端的目的进程的进程名称。如果构造函数的destGuid参数传入目的服务器ID,此时构造出可以进行不同服务器节点进程间通信的进程通信客户端模块client(A);如果构造函数的参数没有传入服务器ID,则构造得到用于本服务器节点进程间通信的进程通信客户端模块client(A)。实例化两种不同的进程通信客户端模块client(A)内部实现是对客户端对象的成员变量m_strDestGuid和m_strDestServerAddr根据构造函数的传参内容赋上不同的初值:当构造函数的destGuid参数具有服务器ID传进来时,m_strDestGuid被赋值传进来的服务器ID值,m_strDestServerAddr被赋值为指向messagebus服务的套接字的文件路径,说明此条消息将来需要发送给messagebus服务去完成消息中转;当构造函数无服务器ID传进来时,m_strDestGuid会被赋值为空,m_strDestServerAddr则会赋值为构造函数传进来的destProName参数,生成进程通信服务端模块所在进程的套接字的文件路径。
在完成客户端类的成员变量赋值之后,创建客户端模块的套接字,此处创建的套接字的类型为调用socket创建的数据报套接字(SOCK_DGRAM)类型。进行套接字bind之前会对sockaddr_un和结构体的成员变量sun_path进行赋值操作,具体赋值是根据调用getpid函数得到的进程号和套接字描述符相结合生成右值(保证此值唯一即可)。此时sun_path的值就是进程通信客户端套接字文件的绝对路径(一般为/tmp生成的套接字文件)。完成套接字的bind之后,会在相应目录下生成相对应的套接字文件。创建此套接字时,对消息的发送和接受的延时时间调用setsockopt函数进行处理。进程通信客户端模块client(A)对发送消息的处理和发送操作:支持消息本体发送和使用protobuf对消息本体进行序列换和反序列换之后的发送。发送消息可以选择是否接受进程通信消息回复,如果选择消息回复,在调用发送函数XipcMsgReq时bool型的reply参数赋值为true即可;如果不需要消息回复,此参数传入false。进程通信客户端模块client(A)发送消息时,采用二次限长发送机制,一次发送类似于一次握手动作,发送消息的内容为消息头结构体msgHead。该结构体包含发送目的地址的服务器ID地址、目的服务器通信服务端模块所在的进程名称、客户端套接字文件的绝对路径(消息来源的客户端)、中转目的服务端套接字路径(消息中转到messagebus服务模块)、消息的类型(不同消息类型的标识)、消息的长度、回复消息类型(是否需要回复消息)。第一次头结构体消息发送成功后,根据实际消息的长度分多次发送。消息一次发送的最大长度为65536,当消息长度小于65536个字节时,消息一次发送;当长度大于65536个字节时,消息会经过多次发送,直至消息被完全发送。
messagebus服务模块MBus(A):
messagebus服务模块MBus(A)对消息处理时机是:当进程通信客户端模块client(A)需要发送跨服务器节点的消息时,进程通信客户端模块client(A)将消息首先发送给messagebus服务模块MBus(A),使messagebus服务模块MBus(A)进行向另外服务器节点发送消息的中转,此过程会发生利用仿真路由表进行目的服务器ID和目的服务器IP地址之间的转换。
messagebus服务模块的内部实现:messagebus服务模块主要有三个实现类,即消息处理的处理类、接受消息的服务类、发送消息的客户类。
消息处理的处理类,主要处理本服务器进程跨节点通信时经过messagebus服务模块MBus(A)中转的过程。此过程在接收到来自进程通信客户端模块client(A)发过的消息头结构体时,得到消息头结构体中的msgDestGuid结构体成员变量,即目的服务器的ID地址。利用仿真路由表查询此服务器ID对应的真实目的服务器IP地址。仿真路由表的创建是系统调用uuid_generate和uuid_unparse函数生成服务器的唯一标识字符串,即服务器ID;调用ioctl函数得到服务器现有真实IP地址。服务器集群的所有的服务器的唯一标识字符串ID和对应的服务器IP地址写入内存文件,生成一张仿真路由表,并对仿真路由表进行定时修改和更新。
消息处理类每次实例化对象时便会下载仿真路由表。当消息处理类得到目的服务器的ID之后,通过服务器的IP地址将消息发送到目的服务器。此发送消息的过程调用了发送消息的客户端模块。发送消息的客户端模块实例化之后在构造函数里面调用ConnectServer成员方法创建一个类型为SOCK_STREAM的流式套接字,在ConnectServer里调用setsockopt对套接字进行套接字关闭延时等待、套接字重用、发送和接受消息延时等设置。调用fcntl函数对套接字文件描述符是指文件描述符标记。调用select函数实现消息事件非阻塞。成员方法消息处理的客户类模块对象创建socket套接字只会对一个端口绑定,此socket的发送唯一服务端就是目的服务器的messagebus服务,所用bind的端口便是messagebus服务监听的端口。当消息发送到目的服务器的messagebus服务之后,messagebus服务实例化的接受消息的服务类的对象接受此条消息。messagebus服务的接受消息服务类的对象接受到消息后就会读取消息头结构体中的MsgDestProName(目的进程名称)结构体成员,将消息发送到目的进程。
上述发送消息的实现时:接收消息的服务类在实例化对象之后创建一个MsgWaitTsk线程。该MsgWaitTsk线程的创建是在服务类的Init初始化的成员方法中调用等待接受消息任务MsgWaitTsk的成员方法实现的。服务类的初始化Init成员方法的内部实现是:调用socket创建流式套接字,监听端口为7328。调用setsockopt函数设置重用套接字和禁止Nagle算法选项。调用listen函数,设置未完成连接队列的最大长度为1024。随后创建MsgWaitTsk线程中开启了等待消息和转发消息的过程。MsgWaitTsk线程内部实现是采用epoll机制实现接受处理消息的高并发处理,调用accept函数获取新的获取连接套接字描述符nRemoteFd。得到连接套接字描述符nRemoteFd之后,创建发送消息至目的进程(MsgDestProName)的线程OnClientConnectedTsk,此线程根据连接套接字描述符nRemoteFd调用recv函数,接收消息。接收到长度正确的消息之后,调用接收消息的服务类对象的成员函数OnMsgHandle,将接收的消息发送到目的进程(MsgDestProName)的服务端模块。接收到的消息的长度是否正确要是对消息本体的长度进行判断之后,将接收消息的服务类对象接收到的消息发送给本服务器节点的目的进程(MsgDestProName)。在发送消息的过程中,实例化进程通信客户端模块,采用本地服务器进程间通信的方式进行进程通信,此过程上述进程间通信客户端模块有详细说明,此处不做详细说明。
进程通信服务端模块:进程通信服务端模块应用场景是:服务器进程服务需要与其它进程之间进行消息通信接收消息时。进程通信服务端模块在构建时,首先实例化一个进程通信服务模块的实现类对象。实例化此实现类对象的构造函数只有一个参数(strProName)传入,此参数便是实例化此进程通信服务类对象的主进程名称。构造函数内部会调用CxipcSocket类中的XipcSocketCreate函数生成进程通信服务端模块的套接字。生成该套接字是内部实现调用socket,创建套接字的类型为数据报套接字(SOCK_DGRAM)类型。与进程通信客户端模块相同,在进行bind之前需要对sockaddr_un的成员变量sun_path进行赋值操作,将domainName变量名称赋值给sun_path。而domainName路径名称就是构造函数传进来的strProName文件名称。经过bind之后在内存执行的路径下生成相应的套接字文件。此处套接字的函数调用和进程通信客户端模块的生成方式相同,此处不做过多的解释说明,只是两者参数传递不同,函数内部会对名称做出判断从而生成不同的套接字文件。前者生成带有进程通信客户端模块标识的套接字文件,后者则生成服务端套接字的文件。套接字创建完成之后,构造函数创建等待接受消息的线程MsgRecvTsk,用于接受进程通信客户端发送过来的消息。消息等待进程MsgRecvTsk的内部实现是调用recvfrom函数接收消息。在调用recvfrom之前调用XipcSockNeedRead对套接字描述符和延时时间进行判断,XipcSockNeedRead函数对套接字描述符的操作是调用select。执行select之后如果返回的值大于0,XipcSockNeedRead函数返回0,此时就会调用recvfrom函数接受消息。recvfrom函数接受消息之后执行OnMsgHandle函数,将数据传输到目的进程(MsgDestProName)通信服务端模块。此时消息便被接收到,利用protubuf对其进行反序列化操作,得到消息本体。OnMsgHandle函数添加消息是一个消息接收的缓冲机制,其内部实现是调用一个传递消息的类Cclient,执行该类的添加数据的成员方法AddMsgData获取数据后,将此Cclient对象加入Cclient的list的容器内。进程通信服务端模块的对象从Cclient的list的容器内部提取带有数据的Cclient,从而得到数据。如果需要消息回复,进程通信服务端模块的对象调用XipcAckMsg成员变量对来自进程通信客户端模块的消息进行回复。消息回复的内部实现直接调用sendto对消息进行回复。
本发明提供的适用于Linux服务器集群的多场景进程间通信方法,可应用于视频综合管理平台项目中的所有进程通信的功能实现。下面列举具体实施例:
1、跨服务器节点的进程通信:
在服务器集群中某一个服务器节点的hplaformds进程需要向其他服务器节点的deviceds进程发送消息时,hplaformds进程调用进程间通信客户类CxipcClient实例化得到进程通信客户端的对象,调用过程为:
进程间通信客户类CxipcClient的构造函数具有两个参数,分别为:destGuid参数和destProName参数;其中,destGuid参数为目的服务器节点ID标识符号,destProName参数是目的进程名称。因为destGuid参数不为空,所以此条消息会经过本服务器节点的messagebus转发,即此条消息需要首先到达本服务器节点的messagebus服务模块。
调用结束后,在/tmp目录下生成进程通信客户端模块的套接字文件。
套接字文件生成之后,说明进程通信客户端模块的套接字已经创建完成。之后执行CxipcClient类里面的消息发送成员方法XipcMsgReq,传入必要的消息本体的参数之后,将消息发送给本服务器节点的messagebus服务模块。本服务器节点一直运行着messagebus服务模块对消息进行监听和仿真路由表的更新。
messagebus服务模块实例化出一个CmsgBus的对象,调用CMsgBus类对象的成员方法WaitMsg等待接受消息,代码实现如下:
成员方法WaitMsg会接受hplaformds服务发过来的消息,接收到消息头结构体msgHead获取目的服务器节点ID地址后,查找仿真路由表得到目的服务器节点的IP地址,根据目的服务器节点IP地址,将该条消息发送到目的服务器节点的messagebus服务模块。
消息到达目的服务器节点的messagebus服务模块后,目的服务器节点的messagebus服务模块构造函数调用Init成员方法创建等待消息线程接受等待的消息,并将消息发送到目的进程。该进程即是destProName的名称。
2、本地服务器节点进程通信:
在服务器集群中某一个服务器节点的hplaformds进程,需要向本服务器节点的deviceds进程发送消息时,hplaformds进程调用进程间通信客户类CxipcClient实例化得到进程通信客户端的对象,函数调用和跨服务器节点进程通信调用函数相同,区别仅在于:在实例化进程通信客户端模块给构造函数的传递参数destGuid赋值为NULL、destProName传入deviceds的名字,然后将消息发送给deviceds进程创建的进程通信服务端模块。
上述两种进程间通信场景采用同一调用函数同一个接口函数,函数调用十分简单易用。
本发明涉及不同场景进程间通信(跨服务器节点和本服务器节点)函数的调用方式、服务器集群内部自建仿真路由表的通信方法。
现有的进程通信技术的功能较为单一,无法同时处理本地进程通信和跨服务器节点通信的功能要求。现有技术在实现本服务器节点和跨服务器节点进程通信时要采用不同进程间通信方式,调用不同的函数去实现功能,过程极为繁琐。在中小型服务器集群内部如果服务器IP地址更换,会对该服务器集群之间的通信造成严重的影响。
本发明提供的适用于Linux服务器集群的多场景进程间通信方法,使不同场景下的进程通信的操作变得简便快捷,本服务器节点进程通信和跨服务器节点进程通信的函数调用采用相同的函数实现。利用仿真路由查询的方式消除服务器集群中增加服务器或修改服务器IP地址对服务器之间进程通信的影响。具体的,仿真路由表实时记录服务器ID和IP地址的对应关系,服务器ID无法更改,即使IP地址更换,根据服务器ID可以查询到服务器IP地址。消息采用message的中转减少了进程服务对监听端口的使用。
以上所述仅是本发明的优选实施方式,应当指出,对于本技术领域的普通技术人员来说,在不脱离本发明原理的前提下,还可以做出若干改进和润饰,这些改进和润饰也应视本发明的保护范围。
- 适用于Linux服务器集群的多场景进程间通信方法
- 适用于Linux服务器集群的多场景进程间通信方法