发明内容
本发明要解决的技术问题在于避免现有技术的不足之处而提出给出了一种远程过程调用RPC的方法,能够实现本地或者基于企业内部网INTRANET或者基于互联网INTERNET的远程过程调用RPC;本发明通过底层方法实现了远程方法调用,能够应用于远程数据访问,实现数据库的逻辑业务中间件。
本发明提出的远程过程调用RPC的方法,在掌握底层实现基础原理的基础上,通过TCP/UDP的方式实现远程方法的入口参数与出口参数的数据交互,通过线程池技术实现过程的并发访问机制。本发明涉及到的远程方法访问与具体应用无关,只要能够开发基于TCP/UDP的应用的开发语言,即仅仅涉及所有开发语言均支持的基本数据类型,开发工具都能够实现远程方法的调用,服务器端与客户端可以使用不同的开发工具和语言分别实现。***可以部署在任何支持TCP/UDP通讯方式的操作***下,支持移动式操作***的远程方法访问。极大的简化了***的部署和实现,对于架构一个客户端Client/服务器端Server模式应用起到了基础框架的作用。
本发明解决所述技术问题可以通过采用以下技术方案来实现:
提出一种基于传输控制协议TCP/用户数据报协议UDP的远程过程调用RPC的方法,用于包括服务器端和客户端的网络***;所述客户端借助基于传输控制协议Transmission Control Protocol/用户数据报协议User Datagram Protocol的套接字Socket与服务器端建立链接。所述方法包括如下步骤:
在服务器端建立***对象池和***线程池;所述***对象池内保存有用于完成过程调用的***接口对象,所述***接口对象被分配唯一的对象标识码IDentity,以及唯一的接口标识码IDentity;从而根据对象标识码ID和接口标识码ID能够唯一地确定***接口对象;所述***线程池包括至少两个能够同时并行工作的工作线程;从而令服务器端与客户端能够按照以下步骤完成远程过程调用Remote Procedure Call,
A. 客户端将调用主体输入的过程调用数据封装为调用数据包,该调用数据包包括对象标识码ID、接口标识码ID和用于完成过程调用需要的设置参数;
B. 步骤A所述客户端借助套接字Socket建立与服务器端的链接;
C. 客户端将步骤A所述调用数据包发送至服务器端;
D. 服务器端根据收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法;
E. 服务器端在对象池中找到空闲的工作线程,将步骤D找到的***接口对象、接口对象执行方法和所述调用数据包中的设置参数输入至工作线程,启动工作线程执行***接口对象的处理过程;
F. 服务器端将工作线程执行***接口对象的结果以返回参数包的形式发送至客户端;
G. 客户端根据收到的返回参数包针对调用主体执行相应操作。
具体地,步骤A所述调用数据包还包括等待返回数据的超时时间,返回数据的存放指针,以及用于表明本次过程调用获得的字节数量的传出参数。
为了确保建立链接过程的完整性,步骤B还包括如下分步骤,
B1. 客户端依据套接字Socket发起与服务器端的链接,
B2. 如果客户端与服务器端建立链接成功,进行步骤C;
B3. 如果客户端与服务器端建立链接失败,终止本次过程调用。
为了防止远程调用过程超时,步骤A所述调用数据包还包括等待返回数据的超时时间,那么步骤C包括如下分步骤,
C1. 客户端将步骤A所述调用数据包发送至服务器端;
C2. 客户端启动返回数据超时等待计时;
同时,步骤G包括如下分步骤,
G1. 比较分步骤C2的返回数据超时等待计时时间与调用数据包中所述等待返回数据超时时间,如果返回数据超时等待计时时间不大于等待返回数据超时时间,执行分步骤G2;如果返回数据超时等待计时时间大于等待返回数据超时时间,终止本次过程调用;
G2. 客户端根据收到的返回参数包针对调用主体执行相应操作。
具体而言,分步骤G2包括如下分步骤,
G21. 解析返回参数包内参数,判断过程调用是否成功;
G22. 向调用主体返回经解析的返回参数包内的参数,供调用主体执行相应操作;
G23. 关闭与服务器端的连接。
服务器端接收到调用数据包后的一种具体处理方案是,所述步骤D包括如下分步骤,
D11. 服务器端判断收到的调用数据包中的对象标识ID和接口标识码ID是否合法;如果判断合法进行分步骤D12;如果判断不合法将过程调用不成功的结果以返回参数包的形式发送至客户端,执行步骤G;
D12. 服务器端根据步骤C收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法。
服务器端接收到调用数据包后的具体处理方案是,服务器端的所述线程池中还包括连接工作线程,那么所述步骤D包括如下分步骤,
D21. 启动连接工作线程;
D22. 将接收到调用数据包排序,并依次对每个调用数据包执行分步骤D23,分步骤D24,以及步骤E,步骤F;
D23. 判断收到的调用数据包中的对象标识ID和接口标识码ID是否合法;如果判断合法进行分步骤D24;如果判断不合法将过程调用不成功的结果以返回参数包的形式发送至客户端,执行步骤G;
D24. 服务器端根据步骤C收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法;
进而所述步骤E包括如下分步骤,
E1. 服务器端搜索对象池中是否有空闲的工作线程,如果有空闲的工作线程,执行分步骤E2;如果没有空闲的工作线程,将调用数据包保持在连接工作线程的排序队列中,返回分步骤D22;
E2. 服务器端在对象池中找到空闲的工作线程,将步骤D24找到的***接口对象、需要执行的接口对象执行方法和所述调用数据包中的设置参数输入至工作线程,启动工作线程执行***接口对象的处理过程。
客户端接收到服务器端发来的返回参数包的具体处理方法是,步骤G包括如下分步骤,
G31. 解析返回参数包内参数,判断过程调用是否成功;
G32. 向调用主体返回经解析的返回参数包内的参数,供调用主体执行相应操作;
G33. 关闭与服务器端的连接。
同现有技术相比较,本发明“基于TCP/ UDP的远程过程调用RPC的方法”的技术效果在于:
1. 开发简单,统一架构下实现与过程调用与具体的应用无关;在本发明给出的远程过程调用框架下,***底层代码实现简单,可复制性强,开发人员不必掌握底层代码实现,***对并行访问,消息报文的封装由统一的接口函数实现,开发人员只需要关注业务特点,开发业务实现代码即可实现应用服务器与客户端的开发;
2. 本发明借租底层接口链接,对***平台没有特别要求,能够在不同平台,不同开发环境下实现远程过程调用RPC;本发明不局限具体的开发语言,只要按照本发明给出的方案,可以实现跨平台,跨开发环境的远程过程调用RPC支持;***报文中传递的数据类型通用于不同的开发语言与开发平台,具备良好的移植特性;
3. 本发明令线程并行执行,利用多核心处理器的并行处理能力,实现远程方法或数据的并行访问;
4. ***可扩展能力强;由于采用底层实现机制,本发明可以根据具体的业务应用进行扩展,包括安全特性,并发特性的扩展实现;例如在网管平台的开发上,为了实现对设备的轮询操作,只需要在主业务线程中添加部分代码即可实现***的功能性扩展。
具体实施方式
以下结合附图所示优选实施例作进一步详述。
本发明提出一种基于传输控制协议TCP/用户数据报协议UDP的远程过程调用RPC的方法,用于包括服务器端和客户端的网络***。所述服务器端由用于实现服务器功能的硬件组成。所述客户端由用于实现客户端功能的终端硬件组成。所述客户端借助基于传输控制协议TCP/用户数据报协议UDP的套接字Socket与服务器端建立链接。所述方法包括如下步骤:
在服务器端建立***对象池和***线程池。所述***对象池内保存有用于完成过程调用的***接口对象,所述***接口对象被分配唯一的对象标识码ID,以及唯一的接口标识码ID。从而根据对象标识码ID和接口标识码ID能够唯一地确定***接口对象。***对象池中用容器的方式保存***接口对象。所谓***接口对象,即能够提供远程方法调用的接口类的实例化,所有接口原型都在接口类中定义,通过实例化方式被远程调用。服务器端启动后,实例化所有接口类,并加载所有***支持的接口对象到对象池中。通过该接口对象的对象标识码ID和接口标识码ID就能确定该接口对象对应的执行方法,即接口对象执行方法。服务端启动后,实例化所有接口类,并加载所有***支持的接口对象到对象池中。
所述***线程池包括至少两个能够同时并行工作的工作线程。如图1所示,服务器端初始化时,所有的线程都属于空闲状态。工作线程可以并行的执行接口对象的方法,***的并行处理能力决定于工作线程数量,一般按照每个核心CPU支持2个并发线程的数量进行设定,线程池中工作线程数量可以在***初始化时输入或者从配置文件中加载。
本发明优选实施例,如图1所示,所述方法的完成远程过程调用RPC需要在客户端100和服务器端200之间进行,本发明令服务器端与客户端能够按照以下步骤完成远程过程调用RPC,
A. 如图1所示,在启用远程过程调用101后,执行102,客户端将调用主体输入的过程调用数据封装为调用数据包,该调用数据包包括对象标识码ID、接口标识码ID和用于完成过程调用需要的设置参数; 所述调用主体可以是终端用户输入,或者来自反馈信息;
B. 步骤A所述客户端借助套接字Socket建立与服务器端的链接;
C. 如图1所示104,客户端将步骤A所述调用数据包发送至服务器端;
D. 如图1所示201,服务器端完成初始化后,服务器端根据收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法;
E. 服务器端在对象池中找到空闲的工作线程,将步骤D找到的***接口对象和所述调用数据包中的设置参数输入至工作线程,启动工作线程执行***接口对象的处理过程;所述工作线程按照设置参数执行接口对象执行方法;
F. 如图1所示206,服务器端将工作线程执行***接口对象的结果以返回参数包的形式发送至客户端;工作线程执行***接口对象的结果就是工作线程按照设置参数执行接口对象执行方法后获得的方法返回值,将该方法返回值封装为返回参数包,该返回参数包体现为数据报文,即返回数据报文;所述返回数据报文通过客户端与服务器端建立的套接字SOCKET连接从服务器端返回给客户端;
G. 客户端根据收到的返回参数包针对调用主体执行相应操作。
具体地,步骤A所述调用数据包还包括等待返回数据的超时时间,返回数据的存放指针,以及用于表明本次过程调用获得的字节数量的传出参数。
本发明优选实施例,在***封装调用数据包时,开发人员采用了模板类的方式实现了调用数据包的封装,可参考下面的消息封装函数伪代码原型,
template <class STR_T> int sendDataStream(int method_id, STR_T* str_method, int time_out, _UC** recv_buff, int& recv_size, int obj_id)
该函数能够生成类成员方法的数据流,并通过套接字SOCKET传递给远程服务器,调用远程对象方法,并将返回数据传出。***采用模板类的方式来实现不同类型的数据结构的融合,采用统一的方式实现传出数据的生成。采用模板类的实现方式是因为传入的结构目前不能确定,只能等到运行的时刻才知道传入方法结构的类型
上述参数的具体定义如下,
int method_id 调用远程对象的方法ID,由宏定义决定;
STR_T* str_method 模板类,需要传递给远程对象的参数结构;
int time_out 等待返回数据的超时时间,单位秒;
_UC** recv_buff 返回数据存放的指针,在调用该函数的函数中声明并申请内存,在调用该函数的函数中删除释放内存(单字节整型);
int& recv_size 传出参数,表明本次远程调用获得的字节数量;
int obj_id 调用远程对象的对象ID;
上述封装的返回值是返回SOCKET函数的返回值,超时或者成功发送。
为了防止远程调用过程超时,步骤A所述调用数据包还包括等待返回数据的超时时间,如图1所示,那么步骤C包括如下分步骤,
C1. 如图1所示104,客户端将步骤A所述调用数据包发送至服务器端;
C2. 客户端启动返回数据超时等待计时;
同时,步骤G包括如下分步骤,
G1. 如图1所示105,比较分步骤C2的返回数据超时等待计时时间与调用数据包中所述等待返回数据超时时间,如果返回数据超时等待计时时间不大于等待返回数据超时时间,执行分步骤G2;如果返回数据超时等待计时时间大于等待返回数据超时时间,执行图1所示107,终止本次过程调用;
G2. 客户端根据收到的返回参数包针对调用主体执行相应操作。
具体而言,分步骤G2包括如下分步骤,如图1所示106,
G21. 解析返回参数包内参数,判断过程调用是否成功;
G22. 向调用主体返回经解析的返回参数包内的参数,供调用主体执行相应操作;
G23. 关闭与服务器端的连接。
为了确保建立链接过程的完整性,步骤B还包括如下分步骤,
B1. 客户端依据套接字Socket发起与服务器端的链接,
B2. 如图1所示103至104,如果客户端与服务器端建立链接成功,进行步骤C;
B3. 如图1所示103至107,如果客户端与服务器端建立链接失败,终止本次过程调用。
服务器端接收到调用数据包后的一种具体处理方案是,如图1所示,所述步骤D包括如下分步骤,
D11. 如图1所示202,服务器端判断收到的调用数据包中的对象标识ID和接口标识码ID是否合法;如果判断合法进行分步骤D12;如果判断不合法,如图1所示205,将过程调用不成功的结果以返回参数包的形式发送至客户端,执行步骤G;
D12. 服务器端根据步骤C收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法。
服务器端接收到调用数据包后的另一种具体处理方案是,如图1所示,服务器端的所述线程池中还包括连接工作线程,那么所述步骤D包括如下分步骤,
D21. 启动连接工作线程;
D22. 将接收到调用数据包排序,并依次对每个调用数据包执行分步骤D23,分步骤D24,以及步骤E,步骤F;
D23. 如图1所示202,判断收到的调用数据包中的对象标识ID和接口标识码ID是否合法;如果判断合法进行分步骤D24;如果判断不合法,如图1所示205,将过程调用不成功的结果以返回参数包的形式发送至客户端,执行步骤G;
D24. 服务器端根据步骤C收到的调用数据包中的对象标识码ID和接口标识码ID在***对象池中找到相应的***接口对象以及接口对象执行方法;
进而所述步骤E包括如下分步骤,
E1. 如图1所示203,服务器端搜索对象池中是否有空闲的工作线程,如果有空闲的工作线程,执行分步骤E2;如果没有空闲的工作线程,将调用数据包保持在连接工作线程的排序队列中,返回分步骤D22;
E2. 如图1所示204,服务器端在对象池中找到空闲的工作线程,将步骤D24找到的***接口对象、需要执行的接口对象执行方法和所述调用数据包中的设置参数输入至工作线程,启动工作线程执行***接口对象的处理过程。
客户端接收到服务器端发来的返回参数包的具体处理方法是,如图1所示106,步骤G包括如下分步骤,
G31. 解析返回参数包内参数,判断过程调用是否成功;
G32. 向调用主体返回经解析的返回参数包内的参数,供调用主体执行相应操作;
G33. 关闭与服务器端的连接。
上述各步骤在本优选实施例可采用如下表所示的伪代码实现:
代码 分析
typedef struct PARA_STRUCT 为固定格式的参数
{ 描述,其定义如下:
_UL device_id; 对象ID
_UL method_id; 接口方法ID
_UL data_struct_size; 接口参数大小
void* para_data; 接口参数结构指针
}PARA_STRUCT;
//执行对象方法核心代码
void Execute_Object_Method (PARA_STRUCT&
_para, TClientConnThread* client) 函数原型,client为SOCKET输出线
{ 程,用于返回结果报文传递
TDevice* device = getDevice(_para.device_id);
Device 为接口对象,从输入参数中
if (device == NULL) { 获得对象ID,并找到接口对象
如果接口对象为空(找不到对应的接
//…… 口对象)
return; 进行错误处理,代码略
} 并返回,不继续执行后续操作
TprocessThread* _idle_thread = _threadpool->
_ getIdleThread (); _threadpool为线程池对象,在线程池
if (_idle_thread == NULL) { 中找到空闲线程
//……
如果没有空闲线程
return; 将消息报文保存在队列中,后续有空
} 闲线程继续处理,代码略
device->setPARA(_para); 返回,不继续执行后续操作
_idle_thread->setDevice(device); 设定对象要执行的参数,描述了要执
_idle_thread->setClient(client); 行的方法
_idle_thread->Resume(); 设定空闲线程执行的对象
} 设定返回结果报文的SOCKET通道
//线程执行体核心代码 线程开始独立执行对象方法(并行)
void TprocessThread::Execute()
{ 当线程RESUME以后,线程的工作状
while(!Terminated){ 态变为BUSY,并执行下面的代码
device->execute_method();
RESULT_STRUCT result = 执行对象的方法,对象方法执行结果
device->getRESULT(); 保存在对象的result结构中,
generatePackage(result); 获得接口对象执行返回的结果集
if(result.result_data){ 进行返回报文的封装操作
delete result.result_data; 如果返回有效数据(指针不为空)
result.result_data = NULL; 删除释放已申请的内存
} 指针设置为空
sendResult(); 发送返回报文
delete[] _data._data_stream 删除返回报文申请的内存
Suspend(); 线程挂起(状态变为IDLE)
}
}
//对象执行方法核心代码
void TDevice::execute_method()
{
//…… 对象执行方法原型,执行前,执行需
要的参数在之前已经通过线程中
int result_value; device->setPARA(_para)方法设定
switch(para_struct.method_id) 在执行具体的方法之前,做参数的校
{ 验工作,代码略
case GET_SYS_DESCRIPTION_METHOD_ID: 返方法回值声明
result_value = Get_sys_description(); 根据参数的方法ID,进行执行方法选择
break;
//……
} 执行选定的方法,并将结果保存到
result_value, 供后续返回结果报文使用
后续代码略。
本发明可以作为数据访问中间件的开发基础。异构数据库的访问是业务应用必须要面对和解决的问题,通过数据访问中间件的方式可以很好的解决这一类型的问题。数据访问中间件通过对数据库访问的封装,实现对不同类型数据库的访问。在本发明给出的远程方法基础上,结合XML(可扩展标记语言:Extensible Markup Language)技术实现对数据集的封装,返回数据集作为远程方法的返回报文,客户端方面增加对XML的解析即可实现业务独立的中间件,客户端不必直接建立与数据库服务器的连接,要替换不同类型的数据库服务器,只需要更换不同的数据库驱动即可,而不需要对客户端做任何类型的改动。
本发明还可用于应用服务中间件的开发。针对具体的业务应用,可以将业务的逻辑独立出来,采用本发明提供的方法实现业务逻辑的封装,客户端作为业务的展现层,不实现具体的业务逻辑,通过本发明设计的远程方法调用,实现对业务逻辑的访问,打造三层架构的***应用。