想了又想,还是没明白咋回事!问题如下:1、IdTCPServerExecute过称中,
Client := TUser(AContext.Data);
........
Memo.Lines.Add(Format('IP:%s的%s用户说:"%s"', [Client.IP,Client.UserName, Msg]));自定义类Clinet(Tuser)的属性,IP,UserName,难道是在IdTCPServerConnect过程中
Client := TUser.Create(AContext.Binding.PeerIP, AUserName,AContext.Binding.PeerPort, AContext);
赋值的吗?2、如果上面的是对的,哪么IdTCPServerExecute,IdTCPServerConnect,IdTCPServerDisconnect,3个过程中的参数AContext
都是同一个?USER类的代码如下type
  TUser = class(TObject)
  private
    FIP, FUserName: string;
    FPort: Integer;
    FSelected: Boolean;
    FContext: TIdContext;
    FLock: TCriticalSection;
    FCommandQueues: TThreadList;
    FListItem: TListItem;
    FWorkSize: Int64;
    procedure SetContext(const Value: TIdContext);
    procedure SetListItem(const Value: TListItem);
  protected
    procedure DoWork(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64);
  public
    constructor Create(const AIP, AUserName: string; APort: Integer;
      AContext: TIdContext); reintroduce;
    destructor Destroy; override;
    procedure Lock;
    procedure Unlock;
    property IP: string read FIP;
    property Port: Integer read FPort;
    property UserName: string read FUserName;
    property Selected: Boolean read FSelected write FSelected;
    property Context: TIdContext read FContext write SetContext;
    property CommandQueues: TThreadList read FCommandQueues;
    property ListItem: TListItem read FListItem write SetListItem;
  end;implementation{$R *.dfm}function GetPercentFrom(Int, Total: Int64): Double;
begin
  if (Int = 0) or (Total = 0) then
    Result := 0
  else if Int = Total then
    Result := 100
  else
  begin
    Result := Int / (Total / 100);
  end;
end;{ TUser }
constructor TUser.Create(const AIP, AUserName: string; APort: Integer;
  AContext: TIdContext);
begin
  FLock := TCriticalSection.Create;
  FIP := AIP;
  FPort := APort;
  FUserName := AUserName;
  Context := AContext;
  FCommandQueues := TThreadList.Create;
end;destructor TUser.Destroy;
begin
  FCommandQueues.Free;
  FLock.Free;
  inherited;
end;procedure TUser.DoWork(ASender: TObject; AWorkMode: TWorkMode;
  AWorkCount: Int64);
var
  NewPercent: string;
begin
  if ListItem <> nil then
  begin
    NewPercent := IntToStr(Trunc(GetPercentFrom(AWorkCount, FWorkSize))) + '%';
    if ListItem.SubItems[1] <> NewPercent then
      ListItem.SubItems[1] := NewPercent;
  end;
end;procedure TUser.Lock;
begin
  FLock.Enter;
end;procedure TUser.Unlock;
begin
  FLock.Leave;
end;procedure TUser.SetContext(const Value: TIdContext);
begin
  if FContext <> nil then
    FContext.Data := nil;
  if Value <> nil then
    Value.Data := Self;
  FContext := Value;
end;procedure TUser.SetListItem(const Value: TListItem);
begin
  if FListItem <> Value then
    FListItem := Value;
  if Value <> nil then
    Value.Data := Self;
end;窗体的部分代码如下:
procedure TFIndex.IdTCPServerConnect(AContext: TIdContext);
var
  Client: TUser;
  AUserName: string;
  lst: TList;
  I: Integer;
begin
  AUserName := AContext.Connection.IOHandler.ReadLn;
  if AUserName = '' then
  begin
    AContext.Connection.IOHandler.WriteLn('NO_USER_NAME');
    AContext.Connection.Disconnect;
    Exit;
  end;
  lst := FUsers.LockList;
  try
    for I := 0 to lst.Count - 1 do
      if SameText(TUser(lst[I]).UserName, AUserName) then
      begin
        AContext.Connection.IOHandler.WriteLn('USER_ALREADY_LOGINED');
        AContext.Connection.Disconnect;
        Exit;
      end;
    Client := TUser.Create(AContext.Binding.PeerIP, AUserName,
      AContext.Binding.PeerPort, AContext);
    lst.Add(Client);
    Client.Lock;
    try
      Client.Context.Connection.IOHandler.WriteLn('LOGINED');
    finally
      Client.Unlock;
    end;
  finally
    FUsers.UnlockList;
  end;
  SendMessage(FormHanlde, WM_REFRESH_USERS, Ord(rpAppendItem), Integer(Client));
end;procedure TFIndex.IdTCPServerDisconnect(AContext: TIdContext);
var
  Client: TUser;
begin
  Client := TUser(AContext.Data);
  if Client <> nil then
  begin
    Client.Lock;
    try
      Client.Context := nil;
    finally
      Client.Unlock;
    end;
    FUsers.Remove(Client);
    SendMessage(FormHanlde, WM_REFRESH_USERS, Ord(rpDeleteItem),
      Integer(Client));
    Client.Free;
  end;
end;procedure TFIndex.IdTCPServerExecute(AContext: TIdContext);
var
  Client: TUser;
  Msg, Cmd: string;
  cmds: TList;
  CmdRec: PCmdRec;
begin
  Client := TUser(AContext.Data);
  if Client <> nil then
  begin
    Client.Lock;
    try
      AContext.Connection.IOHandler.CheckForDataOnSource(250);
      if not AContext.Connection.IOHandler.InputBufferIsEmpty then
      begin
        Msg := AContext.Connection.IOHandler.ReadLn;
        if FormHanlde <> 0 then
        begin
          LockUI;
          try
            Memo.Lines.Add(Format('IP:%s的%s用户说:"%s"', [Client.IP,
                Client.UserName, Msg]));
          finally
            UnlockUI;
          end;
        end;
      end;
      cmds := Client.CommandQueues.LockList;
      try
        if cmds.Count > 0 then
        begin
          CmdRec := cmds[0];
          Cmd := CmdRec.Cmd;
          cmds.Delete(0);
          Dispose(CmdRec);
        end
        else
          Cmd := '';
      finally
        Client.CommandQueues.UnlockList;
      end;
      if Cmd = '' then
        Exit;
      if Pos('SENDF', Cmd) = 1 then
      begin
        if FormHanlde <> 0 then
        begin
          LockUI;
          try
            Memo.Lines.Add(Format('发送文件到%s(IP:%s)', [Client.UserName,
                Client.IP]));
          finally
            UnlockUI;
          end;
        end;
        // SendFileToUser(Client,Trim(Copy(Cmd,6,Length(Cmd))));
      end
      else if Pos('SENDT', Cmd) = 1 then
      begin
        if FormHanlde <> 0 then
        begin
          LockUI;
          try
            Memo.Lines.Add(Format('发送文本信息到%s(IP:%s),文本内容:"%s"',
                [Client.UserName, Client.IP,
                Trim(Copy(Cmd, 6, Length(Cmd)))]));
          finally
            UnlockUI;
          end;
        end;
        SendTextToUser(Client, Trim(Copy(Cmd, 6, Length(Cmd))));
      end;
    finally
      Client.Unlock;
    end;
  end;
end;

解决方案 »

  1.   

    问题2: 都是同一个!再分析问题1:
    A、IdTCPServerConnect 过程中,
    Context.Data := TUser.Create(AContext);B、IdTCPServerDisconnect 过程中,
    FreeAndNil(Context.Data);C、IdTCPServerExecute过称中,
    Client := TUser(AContext.Data);
    Client.UserName = "myname"; //  当然要在登录后赋值结论:Context.Data 是用户数据指针,未赋值时,该数据为 nil , 在不同的事件函数中,可快速地指向用户数据地址,仅此而已。
      

  2.   


    恩,其实我一直不明白的就是IdTCPServerExecute过程中,Client := TUser(AContext.Data);
    后,Client.UserName 会有值。
    我开始以为,这是强行转换。
    后来才明白,这是个指针对象,在IdTCPServerConnect给了值。在这里,只不过转换下形式,引用这个指针对象而已。
      

  3.   

    最开始,我合计,这是个强行转换,把客户端发过来新的AContext,强行转换成了USER,但最后,我没说服自己。因为,不可能转换成功的。
    所以,我开始猜测,难道AContext,在3个过程中,是同一个?只有这样,才能说的过去的……看来,我猜测对了!
      

  4.   

    你理解的差不多了,在indy9里面,对应参数是idpeerthread,indy10里改成idcontext,也就是Indy9里,客户端连接到服务器,服务器就创建一个线程来管理此用户与服务端的通讯,所以,你只要找到对应peerthread就能找到与该客户进行“对话”的方法,indy10里有所改变,参数变成acontext:Tidcontext
    这时候,与客户端与服务器联系的方式就是通过这个acontext,有几个客户端连接,就有几个acontext,你要跟哪个客户端“对话”就使用对应的context,实际完成“对话”的线程在Indy10里被“封装”起来,采用线程池管理,比如有10个客户端与服务器连接,那么相应就会有10个idcontext,而线程池可能有5个(也可能更少或者更多)线程完成这些acontext的“对话”。因此管理好这些连接的idcontext是idtcp编程的关键,但是仅仅idcontext又是不够的,还需要连接的客户端更多的信息,所以通常就自定义一个TUser类来记录连接的客户端更多的信息,然后把acontext.data指针指示这个TUser对象。这样客户端用户信息就完整了。