Remy Lebeauによる専門的な質問とほぼ満足のいく回答によると(ありがとうございます)、アプリケーションに役立つコードを組み合わせようとしています。そして、いくつかの側面が私に不明確なままです。以下のコードを見ると:
- Button3Clickプロシージャを使用してGUIから接続されたクライアントにBroadCastを送信する場合-それは正しい方法ですか(つまり、安全ですか)?
- DBへの接続を作成し、それに何かを実行して、DBへの接続を閉じるDoSomethingSafeメソッドコードと同様のものを入れることはできますか?安全ですか?
- clietnsが20を超えるとアプリケーションがフリーズし、active:= false(button2.clickメソッド)を使用してサーバーの動作を停止したいのはなぜですか?
- TCliContext.ProccessMsg内でTCliContext.BroadcastMessageを使用して、同期なしでそれを呼び出すことはできますか?
- OnConnectメソッドで(Connection.IOHandler.ReadLn())を読み取ることはできますか(ログインデータを含む行を読み取り、DBで確認したいのですが、正しくない場合はすぐに切断しますか?
- 私はどこかで読んだ、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;
以前のヘルプを再度ありがとう