unit GroupMonitor; interface uses Windows, SysUtils, Classes, GroupWebSocket, GroupClient; type TGroupHeartbeatThread = class; TGroupKeepAlive = class; TGroupMonitor = class private FLastTime: DWORD; FGroupHeartbeat: TGroupHeartbeatThread; FGroupKeepAlive: TGroupKeepAlive; FLock: TRTLCriticalSection; FClient: TGroupClient; FRunning: Boolean; FPingInterval: Integer; FPingTimeout: Integer; FKeepAlive: Boolean; procedure SetRunning(const Value: Boolean); procedure SetKeepAlive(const Value: Boolean); class function GetMonitor: TGroupMonitor; public constructor Create; destructor Destroy; override; procedure Start(AClient: TGroupClient); procedure Stop; procedure ReflashLastTime; property Running: Boolean read FRunning write SetRunning; //"pingInterval":25000,"pingTimeout":60000 property PingInterval: Integer read FPingInterval write FPingInterval; property PingTimeout: Integer read FPingTimeout write FPingTimeout; property KeepAlive: Boolean read FKeepAlive write SetKeepAlive; end; TGroupHeartbeatThread = class(TThread) private FGroupMonitor: TGroupMonitor; public constructor Create(AGroupMonitor: TGroupMonitor); procedure Execute; override; end; TGroupKeepAlive = class(TThread) private FGroupMonitor: TGroupMonitor; public constructor Create(AGroupMonitor: TGroupMonitor); procedure Execute; override; end; { TGroupMonitor 一、监控心跳 1.管理TGroupClient的心跳(发送和接收心跳); 2.可以设置心跳间隔时间; 3.设置心跳超时时间; 4.超时重连机制; 二、监控处理GroupClient异常断开 1、异常重连 三、同步与主服务的连接状态 } implementation uses LoggerImport, DateUtils; //var // GrpMonitor: TGroupMonitor; { TGroupMonitor } constructor TGroupMonitor.Create; begin inherited; FPingInterval := 25000; FPingTimeout := 60000; InitializeCriticalSection(FLock); FRunning := False; end; destructor TGroupMonitor.Destroy; begin Stop; DeleteCriticalSection(FLock); inherited; end; class function TGroupMonitor.GetMonitor: TGroupMonitor; begin // if GrpMonitor = nil then // GrpMonitor := TGroupMonitor.Create; // Result := GrpMonitor; end; procedure TGroupMonitor.ReflashLastTime; begin EnterCriticalSection(FLock); FLastTime := GetTickCount; LeaveCriticalSection(FLock); end; procedure TGroupMonitor.SetKeepAlive(const Value: Boolean); begin if FKeepAlive = Value then Exit; FKeepAlive := Value; if FKeepAlive then begin if FGroupKeepAlive <> nil then begin FGroupKeepAlive.Terminate; FGroupKeepAlive.WaitFor; FGroupKeepAlive := nil; end; FGroupKeepAlive := TGroupKeepAlive.Create(Self); FGroupKeepAlive.Resume; end else begin if FGroupKeepAlive <> nil then begin FGroupKeepAlive.Terminate; FGroupKeepAlive.WaitFor; FGroupKeepAlive := nil; end; end; end; procedure TGroupMonitor.SetRunning(const Value: Boolean); begin FRunning := Value; end; procedure TGroupMonitor.Start(AClient: TGroupClient); begin ReflashLastTime; if AClient = nil then Exit; if FRunning then Exit; Stop; FClient := AClient; FGroupHeartbeat := TGroupHeartbeatThread.Create(Self); FRunning := True; end; procedure TGroupMonitor.Stop; begin if not FRunning then Exit; // FClient := nil; if Assigned(FGroupHeartbeat) then begin FGroupHeartbeat.Terminate; try FGroupHeartbeat.WaitFor finally FGroupHeartbeat := nil; end; end; FRunning := False; end; //EnterCriticalSection(LastTimeLock); {开始: 轮到我了其他线程走开} //LeaveCriticalSection(LastTimeLock); {结束: 其他线程可以来了} { TMonitorThread } constructor TGroupHeartBeatThread.Create(AGroupMonitor: TGroupMonitor); begin FGroupMonitor := AGroupMonitor; inherited Create(False); end; procedure TGroupHeartBeatThread.Execute; var AIntervalTime: DWORD; iLoop: Integer; begin while not Terminated do begin AIntervalTime := GetTickCount - FGroupMonitor.FLastTime; if AIntervalTime > FGroupMonitor.FPingTimeout then begin Error(IntToStr(FGroupMonitor.FPingTimeout div 1000) + '60秒内没有收到服务端消息,启动重联.', 'TGroupHeartBeatThread.Execute'); // MainForm.TimerForreconnectgroup.Enabled := False; // MainForm.TimerForreconnectgroup.Enabled := True; Exit; end; if AIntervalTime > FGroupMonitor.FPingInterval then begin FGroupMonitor.FClient.Ping; end; for iLoop := 0 to 19 do begin if Terminated then Exit; Sleep(1000); end; end; end; { TGroupKeepAlive } constructor TGroupKeepAlive.Create(AGroupMonitor: TGroupMonitor); begin FGroupMonitor := AGroupMonitor; inherited Create(True); end; procedure TGroupKeepAlive.Execute; var AIntervalTime: DWORD; iLoop: Integer; begin while not Terminated do begin AIntervalTime := Random(10) + 10; for iLoop := 0 to AIntervalTime - 1 do begin if Terminated then Exit; Sleep(1000); end; if not FGroupMonitor.FClient.Connected then FGroupMonitor.FClient.Connect; end; end; initialization finalization end.