multithreading - 如何向单个客户端而不是所有客户端发送命令?

标签 multithreading delphi tcp connection indy10

我正在用 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/

相关文章:

python - (Python) 使用原始输入停止线程?

multithreading - 低级编程 : How does the OS start a new thread/process?

delphi - Delphi 3 Apply更新

networking - 如何从我 LAN 上的另一台 PC 访问环回适配器

java - java连接两个线程

java - 为什么通常不推荐客户端锁定?

xml - 我如何使用 Indy 接收推送通知?

delphi - 无法从注册表中读取 key

java - TCP Java问题

php - 在 mysql connect (PHP) 中指定协议(protocol)