如何区分来自具有相同 IP 地址的多个客户端的连接?

How do I distinguish connections from multiple clients with the same IP address?

如果客户端具有相同的 IP 和端口,识别客户端的正确方法是什么?如果它们仅通过 LAN 连接,例如ip: 198.162.1.1 端口: 2015. 如果客户端有相同的IP,如何使用其唯一ID检测哪个客户端已断开连接?

TClient = class(TIdServerContext)
  private
  public
    PeerIP      : String;     
    procedure SendMessage(cIP, mStr : String);
  end;

procedure TClient.SendMessage(cIP, mStr : String);
var
  Context: TClient;
  List: TList;
  I: Integer;
begin
  List := Form1.IdTCPServer1.Contexts.LockList;
  try
    for I := 0 to List.Count-1 do
    begin
      Context := TClient(List[I]);
      if (Context.PeerIP = cIP) then
      begin
        Connection.IOHandler.WriteLn(mStr);
        Break;
      end
    end;
  finally
    Form1.IdTCPServer1.Contexts.UnlockList;
  end;
end;

我只存储客户端 IP 并将其用作 ID。

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
  with TClient(AContext) do
  begin
    if AContext.Connection.Connected then
    begin
      PeerIP := Connection.Socket.Binding.PeerIP;
    end;
  end;
end;

可能喜欢ClientID := Connection.Socket.Binding.Handle;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
 //Connection.Socket.Binding.Handle; ?? 
end;

PeerIP 本身不足以唯一识别客户端。想一想当路由器一侧的多个客户端 运行 连接到路由器另一侧的同一服务器 运行 时会发生什么。从服务器的角度来看,客户端将具有相同的 PeerIP(路由器的 IP)。您需要每个客户端的 PeerIP 和 PeerPort 在一起。

  TClient = class(TIdServerContext)
  public
    PeerIP      : String;
    PeerPort    : TIdPort;
    procedure SendMessage(cIP: string; cPort: TIdPort; mStr : String);
  end;

procedure TClient.SendMessage(cIP: string; cPort: TIdPort; mStr : String);
var
  Context: TClient;
  List: TList;
  I: Integer;
begin
  List := Form1.IdTCPServer1.Contexts.LockList;
  try
    for I := 0 to List.Count-1 do
    begin
      Context := TClient(List[I]);
      if (Context <> Self) and (Context.PeerIP = cIP) and (Context.PeerPort = cPort) then
      begin
        Context.Connection.IOHandler.WriteLn(mStr);
        Break;
      end
    end;
  finally
    Form1.IdTCPServer1.Contexts.UnlockList;
  end;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
  with TClient(AContext) do
  begin
    PeerIP := Connection.Socket.Binding.PeerIP;
    PeerPort := Connection.Socket.Binding.PeerPort;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
 ...
end;

或者根本不依赖 IP/Port。自己编一个唯一的ID,比如要求每个client用UserID登录服务器。

  TClient = class(TIdServerContext)
  public
    UserID      : String;
    procedure SendMessage(cUser, mStr : String);
  end;

procedure TClient.SendMessage(cUser, mStr : String);
var
  Context: TClient;
  List: TList;
  I: Integer;
begin
  List := Form1.IdTCPServer1.Contexts.LockList;
  try
    for I := 0 to List.Count-1 do
    begin
      Context := TClient(List[I]);
      if (Context <> Self) and (Context.UserID = cUser) then
      begin
        Context.Connection.IOHandler.WriteLn(mStr);
        Break;
      end
    end;
  finally
    Form1.IdTCPServer1.Contexts.UnlockList;
  end;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
  with TClient(AContext) do
  begin
    // this is just for demonstration. Obviously, you
    // should implement a real protocol with authentication,
    // duplicate login detection, etc...
    UserID := Connection.IOHandler.ReadLn;
  end;
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
begin
 ...
end;