如何向单个客户端而不是所有客户端发送命令? [英] How do I send a command to a single client instead of all of them?

查看:174
本文介绍了如何向单个客户端而不是所有客户端发送命令?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Indy 10编写一个简单的客户端/服务器聊天程序。我的服务器(idtcpserver)向客户端发送命令,客户端应答,但是当连接了多个客户端并且服务器发送命令时,

I am writing a simple client/server chat program with Indy 10. My server (idtcpserver) sends a command to the client, and the client answers, but when more than one client is connected and the server sends a command, all the clients connected send data to the server.

如何将命令发送到指定的客户端,而不是全部?

How I can send a command to a specified client and not all?

推荐答案

命令可以发送到所有连接的客户端的唯一方法是如果你的代码循环通过发送命令的每个客户端。因此,只需删除该循环,或至少将其更改为只发送给您感兴趣的特定客户端。

The only way a command could be sent to all connected clients is if your code is looping through all of the clients sending the command to each one. So simply remove that loop, or at least change it to only send to the specific client that you are interested in.

向客户端发送命令的最佳位置,以避免由于重叠的命令而破坏与该客户端的通信,来自该客户端自己的 OnExecute 事件,例如:

The best place to send a command to a client, to avoid corrupting the communications with that client due to overlapping commands, is from within that client's own OnExecute event, eg:

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
  ...
  if (has a command to send) then
  begin
    AContext.Connection.IOHandler.WriteLn(command here);
    ...
  end;
  ...
end;

如果您需要从其他线程向客户端发送命令,它自己的出站命令队列,然后让那个客户端的 OnExecute 事件发送队列,当它是安全的。其他线程可以在需要时将命令推入队列。

If you need to send commands to a client from other threads, then it is best to give that client its own queue of outbound commands and then have that client's OnExecute event send the queue when it is safe to do so. Other threads can push commands into the queue when needed.

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;

这篇关于如何向单个客户端而不是所有客户端发送命令?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆