有没有办法挂钩到dbx用户会话的WndProc?
背景: dbx DataSnap使用Indy组件进行TCP通信。最简单的形式是,DataSnap服务器是接受连接的Indy TCP服务器。建立连接后,Indy会为该连接创建一个线程,处理该连接的所有请求。
这些用户连接中的每一个都消耗资源。对于具有几百个同时连接的服务器,这些资源可能很昂贵。许多资源可以合并,但我不想总是在每次需要时获取和释放资源。
相反,我想实现一个空闲计时器。在线程完成资源后,计时器将启动。如果线程在计时器过去之前访问资源,则资源仍将“分配”给该线程。但是如果计时器在下次访问之前经过,资源将被释放回池中。下一次线程需要资源时,将从池中获取另一个资源。
我还没有办法做到这一点。我尝试过使用SetTimer,但我的计时器回调永远不会触发。我假设这是因为Indy的线程的WndProc没有调度WM_TIMER。我无法控制此线程的“执行循环”,因此我无法轻松检查事件是否已发出信号。实际上,除非线程正在处理用户请求,否则我的代码都不会执行。事实上,我希望代码能够在任何用户请求之外执行。
原始问题的解决方案或替代方法的建议将同样受到赞赏。
答案 0 :(得分:1)
我们尝试使用TCP连接(没有HTTP传输,因此没有SessionManager)实现跨用户线程共享资源的东西,但遇到了各种各样的问题。最后,我们放弃了使用单个用户线程(设置LifeCycle := TDSLifeCycle.Server
)并在 ServerContainerUnit 中创建了我们自己的FResourcePool
和FUserList
(两个TThreadList
)。它只需要1天就可以实现,而且效果非常好。
以下是我们所做工作的简化版本:
TResource = class
SomeResource: TSomeType;
UserCount: Integer;
LastSeen: TDateTime;
end;
当用户连接时,我们会检查FResourcePool
是否有用户需要的TResource
。如果存在,我们增加资源的UserCount
属性。用户完成后,我们递减UserCount
属性并设置LastSeen
。我们有一个TTimer
,每60秒触发一次,可以释放任何资源UserCount = 0
和LastSeen
超过60秒。
FUserList
非常相似。如果几个小时没有看到用户,我们假设他们的连接被切断(因为如果用户空闲了90分钟,我们的客户端应用会自动断开连接),所以我们以编程方式断开服务器端的用户连接,这也减少了他们对每种资源的使用。当然,这意味着我们必须自己创建一个会话变量(例如CreateGUID();
)并在首次连接时将其传递给客户端。客户端会根据每个请求将会话ID传递回服务器,以便我们知道哪个FUserList
记录是他们的。虽然这是不使用用户线程的缺点,但它很容易管理。
答案 1 :(得分:1)
詹姆斯L也许已经钉了它。由于Indy线程没有消息循环,你必须依赖另一种机制 - 比如只读线程局部属性(如 UserCount 和/或 LastSeem 在他的'示例) - 并使用服务器的主线程来运行TTimer以根据某些规则释放资源。
编辑:另一个想法是创建一个公共数据结构(下面的示例),每次线程完成其工作时都会更新。
警告:仅从头脑编码......可能无法编译......; - )
示例:
TThreadStatus = (tsDoingMyJob, tsFinished);
TThreadStatusInfo = class
private
fTStatus : TThreadStatus;
fDTFinished : TDateTime;
procedure SetThreadStatus(value: TThreadStatus);
public
property ThreadStatus: TThreadStatus read fTStatus write SetStatus;
property FinishedTime: TDateTime read fDTFinished;
procedure FinishJob ;
procedure DoJob;
end
procedure TThreadStatusInfo.SetThreadStatus(value : TThreadStatus)
begin
fTStatus = value;
case fTStatus of
tsDoingMyJob :
fDTFinished = TDateTime(0);
tsFinished:
fDTFinished = Now;
end;
end;
procedure TThreadStatusInfo.FinishJob;
begin
ThreadStatus := tsFinished;
end;
procedure TThreadStatusInfo.DoJob;
begin
ThreadStatus := tsDoingMyJob;
end;
将它放在一个列表中(您喜欢的任何列表类),并确保每个线程都相关联 在该列表中有索引。仅在您不使用时才从列表中删除项目 线程数量不断缩小(缩小列表)。创建新线程时添加项目 (例如,你有4个线程,现在你需要第5个,你在主线程上创建一个新项目。)
由于每个线程在列表上都有一个索引,因此您不需要封装此写入( 呼叫T 在TCriticalSection上。
您可以毫不费力地阅读此列表,在主线程上使用TTimer进行检查 每个线程的状态。因为你有每个线程的完成时间 你可以计算超时。