我正在用 Indy 10 编写一个简单的客户端/服务器聊天程序。我的服务器 (idtcpserver) 向客户端发送命令,客户端回答,但是当多个客户端连接并且服务器发送命令时,< em>所有 连接的客户端向服务器发送数据。
我如何向指定客户端而不是所有客户端发送命令?
最佳答案
可以将命令发送到所有连接的客户端的唯一方法是,如果您的代码循环遍历所有向每个客户端发送命令的客户端。因此,只需删除该循环,或者至少将其更改为仅发送给您感兴趣的特定客户端。
向客户端发送命令的最佳位置是从客户端自己的 OnExecute
事件中发送命令,以避免由于命令重叠而破坏与该客户端的通信,例如:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
...
if (has a command to send) then
begin
AContext.Connection.IOHandler.WriteLn(command here);
...
end;
...
end;
如果您需要从其他线程向客户端发送命令,那么最好为该客户端提供其自己的出站命令队列,然后让该客户端的 OnExecute
事件发送队列这样做是安全的。其他线程可以在需要时将命令推送到队列中。
type
TMyContext = class(TIdServerContext)
public
ClientName: String;
Queue: TIdThreadSafeStringList;
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override;
destructor Destroy; override;
end;
constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil);
begin
inherited Create(AConnection, AYarn, AList);
Queue := TIdThreadSafeStringList.Create;
end;
destructor TMyContext.Destroy;
begin
Queue.Free;
inherited Destroy;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
IdTCPServer1.ContextClass := TMyContext;
end;
procedure TForm1.SendCommandToClient(const ClientName, Command: String);
var
List: TList;
I: Ineger;
Ctx: TMyContext;
begin
List := IdTCPServer1.Contexts.LockList;
try
for I := 0 to List.Count-1 do
begin
Ctx := TMyContext(List[I]);
if Ctx.ClientName = ClientName then
begin
Ctx.Queue.Add(Command);
Break;
end;
end;
finally
IdTCPServer1.Context.UnlockList;
end;
end;
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
var
List: TList;
I: Ineger;
Ctx, Ctx2: TMyContext;
ClientName: String;
begin
Ctx := TMyContext(AContext);
ClientName := AContext.Connection.IOHandler.ReadLn;
List := IdTCPServer1.Contexts.LockList;
try
for I := 0 to List.Count-1 do
begin
Ctx2 := TMyContext(List[I]);
if (Ctx2 <> Ctx) and (Ctx.ClientName = ClientName) then
begin
AContext.Connection.IOHandler.WriteLn('That Name is already logged in');
AContext.Connection.Disconnect;
Exit;
end;
end;
Ctx.ClientName = ClientName;
finally
IdTCPServer1.Context.UnlockList;
end;
AContext.Connection.IOHandler.WriteLn('Welcome ' + ClientName);
end;
procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
var
Ctx: TMyContext;
begin
Ctx := TMyContext(AContext);
Ctx.ClientName = '';
Ctx.Queue.Clear;
end;
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
Ctx: TMyContext;
Queue: TStringList;
begin
Ctx := TMyContext(AContext);
...
Queue := Ctx.Queue.Lock;
try
while Queue.Count > 0 do
begin
AContext.Connection.IOHandler.WriteLn(Queue[0]);
Queue.Delete(0);
...
end;
...
finally
Ctx.Queue.Unlock;
end;
end;
关于multithreading - 如何向单个客户端而不是所有客户端发送命令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14053329/