2.3.3 信道(TCP/IP与IPC)
1.信道工作机制 信道是两个进程或线程间通信的载体,由Tilcon内部API进行调用,用于实现应用程序与GUI引擎之间的数据交换,其工作原理如图2-9所示。每个信道有两个子端,一个用于发送数据,另一个用于接收数据,基于信道的数据收发连接创建并设置成功后,不带GUI引擎的应用程序就可以轻易地与另一台机器上的GUI引擎进行通信。
图2-9 信道工作原理示意图
GUI引擎通常只在它所处的一方创建一个信道子端,所有连接到同一信道的应用进程创建并维护着应用方的唯一信道子端。只有在使用TCP/IP进行通信的情况下例外,此时信道的两个子端都在GUI引擎所在一方创建并维护着,GUI引擎负责识别在指定时间内与之通信的进程。GUI引擎所在方的信道子端支持创建的最大连接数为64。
一个应用程序可以连接各自运行的不同机器上的多个远程GUI引擎,远程信道之间通过信道ID和信道名称进行识别,最大连接数为64。当应用程序调用TRT_StartEx()命令启动GUI引擎时,GUI引擎给应用程序返回一个cid或信道ID号,开发者可以使用任意命名规则对信道命名(Tilcon模板通常使用TRT_cid)。
2.信道与单线程 单线程应用系统是指应用进程只包含一个执行线程,当应用程序通过TRT_StartEx()调用创建与GUI引擎的通信连接和信道时,不创建额外的线程。例如,在一个单线程应用系统中,一个信道专门用于接收GUI通知,另一个信道专门用于传递来自应用程序的数据或命令给GUI。
3.信道与多线程 多线程应用系统是指系统中可以存在一个或多个线程。在多线程应用系统中,必须使用特定的Tilcon多线程支持库。单线程应用系统中的信道原理同样适用于多信道应用系统。若应用系统使用TCP/IP进行通信,则必须使用Tilcon TCP/IP多线程支持库,在创建通信连接和信道时,将新建一个线程用于监测和设置连接超时时间,从而提高应用系统远程实时连接的灵活性。
4.信道与IPC 以下是Tilcon提供的应用进程或线程之间实现IPC通信的显式API接口函数,更多关于API接口函数的详细内容可参考相应的API接口函数。
■ TRT_ChOpen():在当前线程中创建一个信道。
■ TRT_ChClose():异步地关闭当前线程中创建的信道。
■ TRT_ChReceiveX():异步地从参数指定的信道中接收消息。
■ TRT_ChReply():对来自参数指定信道的消息做出回复。
■ TRT_ChConnect():连接参数指定线程中的信道到远程信道上。
■ TRT_ChDisconnect():断开当前线程中的信道与远程信道的连接。
■ TRT_ChGetName():获取参数指定信道ID对应的信道名称。
■ TRT_ChSend():异步地向参数指定的信道发送消息并等待回复。
■ TRT_ChTrigger():异步地触发参数指定的信道。
■ TRT_ChReceive():接收来自当前线程中信道的消息。
■ TRT_ChGetID():获取参数指定的远程信道名称对应的信道ID。
使用IPC进行通信,每个线程必须创建自己的信道子端,线程之间不允许共享信道子端,也就是说执行API命令TRT_xxx()的每个线程都必须执行TRT_StartEx()命令,其返回的cid值也必须是执行其他API命令的cid参数。Tilcon信道机制基于发送/接收/应答模型,同一机器上的线程间通信和不同机器间的TCP/IP通信都是使用本地IPC。这样,一个线程A创建信道子端后,另一个线程B就可以连接到该信道子端,然后线程A就可以发送TRT_GetInput()命令给线程B,线程B收到后回复线程A请求的数据。
5.信道返回代码 不同模式下的信道返回代码见表2-3至表2-6。
表2-3 TRT_GetInput()(TRT_NO_BLOCK模式)命令的返回代码
表2-4 TRT_GetInput()(TRT_BLOCK模式)命令的返回代码
表2-5 TRT_ChReceive()(TRT_BLOCK模式)命令的返回代码
表2-6 TRT_ChReceive()(TRT_NO_BLOCK模式)命令的返回代码
[注意]信道名称最大长度为32字节,超过32字节将导致不可预期的返回代码。
6.信道生命周期 信道的生命周期分为以下三个阶段:
连接阶段:在两个信道子端之间建立一个通信连接;
通信阶段:在两个信道子端之间进行消息收发;
终止阶段:两个信道子端之间的通信连接被终止。
7.信道与架构 Tilcon信道的通信架构主要有以下三种:
(1)Tilcon GUI线程与Tilcon内核引擎通信,且两者在同一机器上。这种情况下,两个线程通过本地操作系统提供的进程间通信(IPC)进行信息交互。
(2)Tilcon GUI线程与远程Tilcon内核引擎通信,且两者在不同一机器上,两者基于的操作系统也可能不同。这种情况下,两个线程通过TCP/IP网络协议栈进行信息交互。此时,Tilcon GUI线程尝试与远程的Tilcon内核引擎建立连接,远程的GUI内核引擎必须处在运行状态,并在指定的Socket端口上侦听其他机器的连接请求。
(3)Tilcon GUI线程与本地其他线程通信,且两者在同一机器上。这种情况下,两个线程通过Tilcon提供的API接口进行信息交互,其底层依赖的也是本地操作系统提供的进程间通信(IPC)。
不同的通信架构,在信道生命周期的每个阶段调用的相关API有所不同,见图2-10至图2-12。
图2-10 同一机器上的GUI线程与Tilcon内核引擎通过本地IPC通信
图2-11 不同机器上的GUI线程与Tilcon内核引擎通过TCP/IP通信
图2-12 同一机器上GUI主线程与其他线程通过本地IPC通信
(1)GUI线程与本地的GUI内核引擎通信
连接阶段:GUI线程调用TRT_StartEx()接口启动本地内核引擎,若用户未通过参数指定等待本地内核引擎响应的超时时间,则使用默认超时等待时间(10秒)。若在10秒内,内核引擎未正常启动或响应GUI线程,则默认为内核引擎启动失败。若内核引擎已经由其他线程启动,则调用TRT_StartEx()接口不会再次启动内核引擎。同时,创建一个信道对象,并与内核引擎建立一条通信链路。
通信阶段:GUI线程调用TRT_GetInput()接口从事件描述数据队列中获取下一个TRT_ReceiveData类型的数据,若队列中无数据,则阻塞等待下一个数据的到来(TRT_BLOCK)或结束GUI线程(TRT_NO_BLOCK)。TRT_GetInput()接口是GUI应用程序与GUI内核引擎通信的主要方式。当发生某个事件时,GUI内核引擎将检测该事件是否触发通告消息或回调操作,若触发通告或回调,则准备并推送一个描述事件信息的TRT_ReceiveData结构体到事件描述数据队列中。其他线程也可以通过TRT_ChSend()或TRT_ChTrigger()接口发送消息到GUI线程的事件描述数据队列中。GUI线程调用TRT_SetValues()接口设置GUI界面对象及其组件的属性值,调用TRT_GetValues()接口获取GUI界面对象及其组件的属性值。
结束阶段:GUI线程调用TRT_Exit()接口,告知GUI内核引擎退出当前GUI线程,GUI引擎将删除内存中的所有窗口,并同步告知连接GUI引擎的所有进程,当前GUI线程将退出(code = TRT_window,state = TRT_exit_all)。
(2)GUI线程与远程GUI内核引擎通信
连接阶段:GUI线程调用TRT_StartEx()创建一个信道对象,并建立信道与远程内核引擎的TCP/IP连接,若用户未通过参数指定等待远程内核引擎响应的超时时间,则使用默认超时等待时间(60秒)。若在60秒内,远程内核引擎未响应GUI线程,则认为与远程内核引擎的连接创建失败。TRT_StartEx()接口调用不会启动远程主机上的GUI引擎,所以在调用TRT_StartEx()之前,远程GUI内核引擎必须已经启动运行,否则TRT_StartEx()调用将失败。远程GUI引擎可以通过-t选项进行启动。
通信阶段:GUI线程调用TRT_GetInput()接口从事件描述数据队列中获取下一个TRT_ReceiveData类型的数据,若队列中无数据,则阻塞等待下一个数据的到来(TRT_BLOCK)或结束GUI线程(TRT_NO_BLOCK)。当发生某个事件时,GUI内核引擎将检测该事件是否触发通告消息或回调操作,若触发通告或回调,则准备并推送一个描述事件信息的TRT_ReceiveData结构体到事件描述数据队列中,其他线程也可以通过TRT_ChSend()或TRT_ChTrigger()接口发送消息到事件描述数据队列中。调用TRT_SetValues()接口设置GUI界面对象及其组件的属性值。调用TRT_GetValues()接口获取GUI界面对象及其组件的属性值。
结束阶段:GUI线程调用TRT_Exit()接口,告知GUI内核引擎退出当前GUI线程,GUI引擎将删除内存中的所有窗口,并同步告知连接GUI引擎的所有进程,当前GUI线程将退出(code = TRT_window,state = TRT_exit_all)。
(3)GUI线程与本地其他线程的通信
连接阶段:GUI线程调用TRT_StartEx()接口启动本地内核引擎,若用户未通过参数指定等待内核引擎响应的超时时间,则使用默认超时等待时间(10秒)。若在10秒内,内核引擎未正常启动或响应GUI线程,则默认为内核引擎启动失败。若内核引擎已经由其他线程启动,则调用TRT_StartEx()接口不会再次启动内核引擎。同时创建一个信道对象,并建立一条与内核引擎的通信链路。其他线程通过TRT_ChOpen()接口创建一个信道,然后通过TRT_Connect()接口与GUI线程的信道建立连接。
通信阶段:GUI线程调用TRT_GetInput()接口从事件描述数据队列中获取下一个TRT_ReceiveData类型的数据,若队列中无数据,则阻塞等待下一个数据的到来(TRT_BLOCK)或结束GUI线程(TRT_NO_BLOCK)。当发生某个事件时,GUI内核引擎将检测该事件是否触发通告消息或回调操作,若触发通告或回调,则准备并推送一个描述事件信息的TRT_ReceiveData结构体到事件描述数据队列中。GUI线程也可以通过TRT_GetInput()接口获取其他线程发送的消息,通过TRT_Reply()接口回复其他线程由TRT_ChSend()接口发出的消息,通过TRT_ChTrigger()或TRT_ChSend()接口发送消息给其他线程。其他线程通过TRT_ChTrigger()或TRT_ChSend()接口发送消息到GUI线程的事件描述数据队列中,通过TRT_ChReceive()接口接收GUI线程发送的消息,通过TRT_Reply()接口回复GUI线程由TRT_ChSend()接口发出的消息。
结束阶段:GUI线程调用TRT_Exit()接口,告知GUI内核引擎退出当前GUI线程,GUI引擎将删除内存中的所有窗口,并同步告知连接GUI引擎的所有进程,当前GUI线程将退出(code = TRT_window,state = TRT_exit_all)。其他线程通过TRT_ChDisconnect()接口中断本线程信道与GUI线程信道的连接,通过TRT_Close() 接口关闭本线程信道。
8.多屏支持 Tilcon对使用X11(VxWorks、Linux等)或WindML(VxWorks)图形库的所有平台都支持多屏显示。为每个信道配置系统多屏显示支持,需要进行如下操作:
➢ 添加显示器地址到TRT_StartData结构体中
➢ TRT_Start()接口调用时,在实参中使用掩码TRT_STARTDATA_DISPLAY指定使用添加到TRT_StartData结构体中的显示屏,而不是系统默认显示屏
➢ 使用关联的信道连接ID修改显示屏
(1)添加显示器地址到TRT_StartData结构体中 添加显示器地址到TRT_StartData结构体时,对于不同的视窗系统,格式有所不同。
①对于X11平台,用户必须提供X-Server的IP地址、显示器索引值、X-Server索引值3项信息,格式为XServerIP:DisplayID.XServerID。
②对于使用WindML图形库的平台,用户必须提供唯一的Tilcon应用程序名称和显示器索引值,格式为ApplicationName:DisplayID。
以下是在X11多屏显示平台上使用远程主机上某个显示屏的配置示例。
/* initialize the TRT_StartData structure based on OS */ TRT_StartDataStartData; StartData.Os_Env = TRT_VXWORKS; /*OS*/ /* specify the IP:DISPLAY of the XServer */ StartData.Display = "192.168.129.185:0.0"; StartData.IPAddr = NULL; StartData.AppName = "appName"; StartData.Userprog = "userProg"; StartData.Flags = 0;
若X-Server在本地主机上,IP地址部分可以忽略,Tilcon GUI引擎在X11平台上默认使用的显示屏是“:0.0”,在使用WindML图形库的平台上默认使用的显示屏是“disp0:0”。
(2)指定使用添加到TRT_StartData结构体中的显示屏 TRT_StartEx()接口函数的定义如下:
int TRT_StartEx ( unsigned long Mask, /*Describes members of TRT_StartData*/ TRT_StartData *pTRT_StartData; /*Contains connection data*/ )
在调用TRT_StartEx()接口时,通过Mask实参值指定使用TRT_StartData结构体中指定的显示屏,接口调用如下:
TRT_StartEx(TRT_STARTDATA_DISPLAY | TRT_STARTDATA_IPADDR, StartData);
(3)使用关联的信道连接修改显示屏 调用TRT_StartEx()接口后,将得到一个信道ID(StartData.CID),该信道ID可用于修改使用的显示屏。