在Delphi应用程序中,服务器代码通知多个客户端数据更改的首选方法是什么?

21
我有一个大型的Delphi应用程序,其中包含核心服务器代码来保存我的数据。在同一个应用程序中,用户可以打开和关闭多个非模态客户端窗体来查看这些数据。数据更改分为两种类型 - 重要的(例如结构性更改,如添加或删除数据)和次要的,例如更改数据值。已经打开的客户端窗体必须在短时间内更新以显示更改后的数据。这不是一个数据库,我的“服务器”使用自己的数据结构,因此我的解决方案可能忽略了可能在正式数据库结构中可用的标准技术。话虽如此,我现在已经重复使用我的解决方案很多次了,所以我想问问是否有官方技术和可能简化我的代码的Delphi组件。我即将转向多线程代码,这使得问题对我来说更加相关。
我使用两种方法:
  1. 时间戳。 "服务器"代码维护一个Int64值,该值取自QueryPerformanceCounter。客户端窗体在每300毫秒的计时器上检查此值,并在其时间戳与服务器的时间戳不同时进行更新。我想这就是我的“拉取”解决方案。
  2. 接口通知。 "服务器"代码维护从TInterfaceList派生的类,具有AddClient和RemoveClient方法,用于注册一个简单的公共客户端通知接口。每个客户端在创建时向此列表注册自身,并在销毁时注销。服务器上的数据更改会触发对该列表的迭代,调用每个客户端以通知其更改。我想这就是我的“推送”解决方案。
我喜欢接口,解决方案2似乎很好,因为它避免了计时器和易于调试(尽管注销调用可能存在销毁顺序问题)。也有潜在的性能影响,因为很可能每秒可能有数千个数据更改,我必须小心使用BeginUpdate / EndUpdate机制将我的许多服务器数据更改转换为一个实际的通知调用。最终,我需要某种类型的计时器来将调用聚合到一个温和的显示窗体更新中。

这两种解决方案都很好,我在两者之间犹豫不决。对于多线程的解决方案,我肯定存在其他我所不知道的问题。欢迎任何评论。我正在使用XE2。


2
+1,好问题。我正在为我的客户端/服务器应用程序使用方法1。 - jpfollenius
6
我们采取了第二种方法。客户端保持连接开启状态,当一个客户端做出更改时,服务器会通知其他客户端,每个客户端自行决定是否需要采取行动。 - Marjan Venema
有一些开源的消息代理,可以向所有已经“订阅”特定兴趣领域(称为“主题”)的客户端广播命令或文档,即使这些客户端当前没有在监听。这种发布/订阅通信模式可以在Delphi中使用本地客户端库。 - mjn
+1. 我认为Firebird使用第二种方法来实现“事件”。我们在一个应用程序中使用事件。Firebird事件功能 - EMBarbosa
2个回答

8

您需要考虑当客户数量增加时想要发生什么,然后在两个恶中做出决定:

  • 如果我的性能下降了,但可以确保应用程序中的所有数据始终是最新的和正确的(那么您需要使用观察者模式)
  • 如果为了提高性能,在某些地方数据落后于其他地方是否可以接受(那么您可以使用轮询,并在轮询迭代导致过多减速时使间隔变长)

我不喜欢轮询,因为它通常会导致非常复杂的解决方案(至少是我尝试过的东西,也许我当时做错了)。

我将使用接口在Delphi中实现Observer Pattern,您可以使用thisthis作为起点。


这个参考链接非常好,它提供了演示代码并清晰地记录了接口解决方案。+1 并已接受。http://itte.no/delphi/ObservedDemo.htm - Brian Frost
@BrianFrost 很高兴能够帮助到您。 - Jeroen Wiert Pluimers

1

我使用了Windows API来解决类似这样的问题。但是我相信我的方法更简单。在我的应用程序中,我甚至不知道“客户端”的数量,也不知道哪些窗体实际上是客户端。

我的做法如下:

  1. 向由我的应用程序打开的所有窗体(screen.forms[X])广播一个Windows消息。该消息的WParam参数包含指向记录的指针,该记录包含有关事件的信息。此外,不同的操作会广播不同的消息。例如,DB更新使用WM_RECORDUPDATE

  2. Windows(客户端)以以下方式侦听消息:

    procedure RecordUpdateMessage(var msg: TMessage); message WM_RECORDUPDATE;

过程RecordUpdateMessage读取由msg.WParam指向的记录,并根据记录中的数据决定是否对数据库中的记录的更新、插入或删除作出反应。


是的,这确实可行,我已经使用了这个解决方案,但它缺乏结构,您必须小心记录您的消息。 这相当于拿着扩音器在田野上与几个人交谈! - Brian Frost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接