根據幾個問題,幾乎satysfy回答雷米Lebeau(再次感謝你)的一個特別的我試圖結合我的應用程序的代碼有用。 還有幾個方面給我不清楚。當你看到下面的代碼:TIdServer,關於再次同步
- 當我使用Button3Click過程從GUI發送廣播到連接的客戶端 - 是正確的方法(我的意思是:這是安全的)?
- 我可以放入類似於DoSomethingSafe方法的代碼,在其中創建與數據庫的連接,對其執行操作並關閉與數據庫的連接?它安全嗎?
- 爲什麼我的應用程序凍結時,有超過20 clietns,我想通過使用其active:= false(button2.click方法)停止工作服務器?
- 我可以在TCliContext.ProccessMsg中使用TCliContext.BroadcastMessage,只是在沒有任何同步的情況下調用它?我可以在OnConnect方法中讀取(Connection.IOHandler.ReadLn())(我想要用登錄數據讀取行並在數據庫中檢查它,然後當它不正確時立即斷開連接嗎?
- 我在某處讀取,使用IdSync有時危險(如果有什麼內部使用它錯了),所以我有最後一個問題:什麼是更好的解決方案,以達到全局變量或VCL對象
我的示範代碼如下:?
type
TCliContext = class(TIdServerContext)
private
Who: String;
Queue: TIdThreadSafeStringList;
Activity_time: TDateTime;
Heartbeat_time: TDateTime;
InnerMessage: String;
procedure BroadcastMessage(const ABuffer: String);
procedure SendMessageTo(const ADestUser: String; const ABuffer: String);
public
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override;
destructor Destroy; override;
procedure ProccessMsg;
procedure DoSomethingSafe;
procedure info_about_start_connection;
end;
procedure TCliContext.BroadcastMessage(const ABuffer: String);
var
cList: TList;
Count: Integer;
CliContext: TCliContext;
begin
cList := Server.Contexts.LockList;
try
for Count := 0 to cList.Count - 1 do
begin
CliContext := TCliContext(cList[Count]);
if CliContext <> Self then
CliContext.Queue.Add(ABuffer);
end;
finally
Server.Contexts.UnlockList;
end;
end;
procedure TCliContext.SendMessageTo(const ADestUser: String;
const ABuffer: String);
var
cList: TList;
Count: Integer;
CliContext: TCliContext;
begin
cList := Server.Contexts.LockList;
try
for Count := 0 to cList.Count - 1 do
begin
CliContext := TCliContext(cList[Count]);
if CliContext.Who = ADestUser then
begin
CliContext.Queue.Add(ABuffer);
Break;
end;
end;
finally
Server.Contexts.UnlockList;
end;
end;
constructor TCliContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil);
begin
// inherited Create(AConnection, AYarn, AList);
inherited;
Queue := TIdThreadSafeStringList.Create;
end;
destructor TCliContext.Destroy;
begin
Queue.Free;
inherited;
end;
procedure TCliContext.ProccessMsg;
begin
InnerMessage := Connection.IOHandler.ReadLn();
TIdSync.SynchronizeMethod(DoSomethingSafe);
// is it ok?
end;
procedure TCliContext.info_about_start_connection;
begin
MainForm.Memo1.Lines.Add('connected');
end;
procedure TCliContext.DoSomethingSafe;
begin
MainForm.Memo1.Lines.Add(InnerMessage);
end;
和代碼核心與GUI
procedure TMainForm.BroadcastMessage(Message: string);
var
cList: TList;
Count: Integer;
begin
cList := IdTCPServer.Contexts.LockList;
try
for Count := 0 to cList.Count - 1 do
TCliContext(cList[Count]).Queue.Add(Message);
finally
IdTCPServer.Contexts.UnlockList;
end;
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
IdTCPServer.ContextClass := TCliContext;
end;
procedure TMainForm.IdTCPServerConnect(AContext: TIdContext);
begin
TCliContext(AContext).Queue.Clear;
TCliContext(AContext).Heartbeat_time := now;
TCliContext(AContext).Activity_time := now;
TIdSync.SynchronizeMethod(TCliContext(AContext).info_about_start_connection);
// is it safe?
end;
procedure TMainForm.IdTCPServerExecute(AContext: TIdContext);
var
tmplist, Queue: TStringlist;
dtNow: TDateTime;
begin
dtNow := now;
tmplist := nil;
try
Queue := TCliContext(AContext).Queue.Lock;
try
if Queue.Count > 0 then
begin
tmplist := TStringlist.Create;
tmplist.Assign(Queue);
Queue.Clear;
end;
finally
TCliContext(AContext).Queue.Unlock;
end;
if tmplist <> nil then
begin
AContext.Connection.IOHandler.Write(tmplist);
TCliContext(AContext).Heartbeat_time := dtNow;
end;
finally
tmplist.Free;
end;
if SecondsBetween(dtNow, TCliContext(AContext).Heartbeat_time) > 30 then
begin
AContext.Connection.IOHandler.WriteLn('E:');
TCliContext(AContext).Heartbeat_time := dtNow;
end;
if SecondsBetween(dtNow, TCliContext(AContext).Activity_time) > 6 then
begin
AContext.Connection.Disconnect;
Exit;
end;
TCliContext(AContext).ProccessMsg;;
end;
procedure TMainForm.Button1Click(Sender: TObject);
begin
IdTCPServer.Active := true;
end;
procedure TMainForm.Button2Click(Sender: TObject);
begin
IdTCPServer.Active := false;
// here application freezes when there are more then tens active clients
end;
procedure TMainForm.Button3Click(Sender: TObject);
begin
BroadcastMessage('Hello');
// is it safe and correct?
end;
更新(你的出色答卷後,最後一個問題)做簡單(代碼長度較短),我可以使用TIdNotify類象下面這樣:
TMyNotify.Create(1, 'ABC').Notify;
。
type
TMyNotify = class(TidNotify)
public
faction: string;
fdata:string;
procedure DoNotify; override;
procedure action1();
procedure action2();
constructor Create(action:integer;fdata:string); reintroduce;
end;
constructor TMyNotify.Create(action:integer;fdata:string); reintroduce;
begin
inherited Create;
faction:=action;
fdata:=data;
end;
procedure TMyNotify.action2()
begin
//use fdata and do something with vcl etc.
end;
procedure TMyNotify.action2()
begin
//use fdata and do something with vcl etc.
end;
procedure TMyNotify.DoNotify;
begin
case action of
1: action1()
2: action2()
end;
end;
再次感謝您對以前的幫助
優秀和完善的飲食。我很感激。但是,如果可以,請回答在我的主要問題末尾添加的TidNotify示例是否正確? – Artik
是的,這將工作正常。 –
這是我見過有關使用Indy實現tcp服務器的最佳職位之一。它總結了我在過去4年中所學到的。 @RemyLebeau謝謝。 – MikeT