What is the proper way to identify clients if they have the same IP and ports? If they are only connected via LAN, e.g. ip: 198.162.1.1 port: 2015. How do I detect which client has disconnected using its unique ID if they have the same IP?
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;
I'm only storing the client IP and using it as an 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;
Maybe like ClientID := Connection.Socket.Binding.Handle;
procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
//Connection.Socket.Binding.Handle; ??
end;
The PeerIP alone is not unique enough to identify a client. Think of what happens when multiple clients running on one side of a router connect to the same server running on the other side of the router. The clients will have the same PeerIP (the router's IP) from the server's perspective. You need each client's PeerIP and PeerPort together.
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;
Or simply don't rely on IP/Port at all. Make up your own unique ID, such as requiring each client to login to the server with a 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;