在编制工程时,有时需要在两个客户端间进行数据通信。比如,客户端A和客户端B需要实现聊天功能,当客户端A在画面中敲入一行文字“你好!”时,希望在客户端B的相应画面中立刻收到并显示这行文本。同样,客户端B也可以向客户端A发送文本。
在老版本软件中,实现这项功能将是一件很麻烦的事。我们自然想到使用数据库点来进行通讯。我们可以在客户端A中建立一个数据库点AtoB,通过远程数据源将其参数DESC连接到客户端B中的AtoB.DESC上,当客户端A画面输入文字时,立刻将其赋值给AtoB.DESC,由数据库通知另一端的AtoB.DESC发生变化,还要在客户端B上编写数据改变脚本,当AtoB.DESC改变时通知客户端B的画面做相应反应。同样,重复上一过程实现由客户端B到客户端A的数据通知,而且我们需要再创建一对新的数据库点BtoA,因为聊天过程中数据往返是并行的,所以通讯应该在两对数据库点中进行。
倘若我们发送的不仅仅是简单文本,而是其他信息呢?比如:一条包含若干整型、实型、字符串等信息的数据,一条关于画面切换、脚本执行的指令文本。尽管依然可以通过一个数据库点的DESC参数进行传递,可是在接收端如何将所接收到的信息按期望的格式解析呢?也许可以考虑再创建若干数据库点,每个数据库点只传递一个数据,这样一来又带来新的问题:无法预知数据的个数、格式,解析这些数据也会带来大量脚本编写工作;如果是多个客户端间通讯,那么上面所说的工作将要重复的次数=从m个客户端中取出2个客户端的组合个数,例如:从3个客户端中取出2个客户端的组合个数为3、从10个客户端中取出2个客户端的组合数是50。那么这将是一项令人望而却步的工作。另外,新增的数据库点无疑对项目成本来说是个挑战。
有没有一种手段,可以不使用数据库点就能实现客户端间数据通信,而且传递的数据以规范的形式发送和接收,并提供方便的解析方法?答案是:有。紫金桥软件6.5版本新增的会话组件就可以专门解决这类问题。
简介
会话组件是一种实现客户端之间通讯的窗口组件。它通过同一数据网络中的某个DB作为通讯中介,在不同客户端之间实现异步数据通信,其运行的一般原理图如下。
概念介绍
客户端:指view.exe或infoview.ocx(IE客户端)。
通信组:在一个网络中所有需要相互通信的客户端组成了一个通信组。这个网络可以是以太网网络,可以是串口网等。通信组中的任何一个成员均可以和组中其他成员进行数据通信。通信组可以交叉,即一个客户端可以同时为两个通信组中的成员。
会话名:在一个通信组中,每个会话组件对象在通信时使用的唯一标识。
中介节点:在一个通信组中,为所有成员客户端提供通讯媒介的网络节点。同一个组中的所有客户端的中介节点必须指向该网络中的同一个节点。这个节点可以是这个网络中的任意一个有DB.exe运行的节点,该节点所在计算机中的客户端可以不参与数据通信。
具体实现
1. 配置中介数据源
选定中介节点后,在需要进行数据通信的客户端中建立指向中介节点的数据源,如果本机恰好为中介节点,那么使用“本地”数据源就可以了。
2. 创建组件对象
进入客户端工程的组态环境中,创建一个窗口,然后打开子图选择画面,找到“组件、复杂精灵/高级”选项卡,双击“会话组件”图标,一个会话组件被创建在当前窗口中,将其命名。
3. 配置组件对象
双击组件,出现配置界面,如下图所示:
在“数据源”处选择事先指定的中介数据源。
在“自身名称”处填写本会话组件对象的会话名。
在“对方名称”处填写当前发送数据的目标会话组件对象的会话名。
4. 数据发送
数据发送的是通过会话组件的提供的两个函数来实现的:
BOOL Send(String FuncionName, ObDataTable Tab)
BOOL SendTo(String DestName, String FuncionName, ObDataTable Tab)
这两个函数的功能是向目标客户端发送一条信息,其中参数Tab为ObDataTable 类型的对象指针,Tab中包含了本次发送的所有信息。参数DestName为指定的目标客户端的会话名。也就是说,如果使用函数Send则目标客户端为组态时指定的客户端,如果使用函数SendTo则可以动态指定目标客户端。
参数FuncionName为目标客户端会话组件所在窗口的自定义函数名,这个函数是回调函数,当目标客户端收到这条信息后会自动调用这个窗口函数。其函数形式规定为:
void FuncName(String SrcName, ObDataTable& Tab)
其中参数SrcName为本条信息的发送客户端的会话名,Tab为发送的内容。
5. 数据接收
数据接收是通过上述回调函数来处理的。在接收端会话组件对象所在窗口中创建回调函数,注意回调函数的名字及参数类型一定要与规定一致。用户可以在回调函数体内编写收到信息后的处理动作。
在一个双向数据通信的结构体系中,一个客户端既是数据发送端同时也是数据接收端,所以每个客户端都要实现数据发送和数据接收。
进阶
1. 会话组件对象与客户端
会话组件的本质是窗口组件,这就意味着同一客户端中可以创建多个会话组件对象,但是每个会话组件对象应该拥有唯一的会话名。可以通过让这些会话组件对象指向不同中介数据源,来实现与不同通信组成员客户端的通讯。
2. 动态切换中介数据源
假设在组态时指定了会话组件的中介数据源为DS1,那么在运行时可以通过调用数据源函数SetNetAddr来动态切换其指向的网络结点,从而切换中介数据源。
3. 如何发送广播
通过会话组件提供的函数void GetUserNames(String Array Names),可以在运行时得到当前通信组中所有通信成员的会话名,然后针对所有会话名发送信息以便达到广播的目的。
4. 通过会话组件能传递哪些数据
从会话组件的发送及回调函数来看,数据是通过数据表对象(ObDataTable)来传递的,ObDataTable是一种比较实用的表格,可以同时传递多行多列的文本、数值等数据,但是无法直接传送文件。
5. 关于超时
因为涉及网络通信,所以在网络状况较差甚至是断开的情况下无法保证数据通信的畅通性和及时性,因此需要自行处理发送超时。一般在接收到数据后应该马上返回一条信息告知发送端本条数据已经成功接收,如果发送端没有在规定时间内收到反馈信息,则认为是超时。