Delphi:如何发送文本到一个特定的客户端连接到服务器套接字知道他们的本地IP地址



我正在为我的IT班开发一个基于文本的小型网络消息传递平台。

一切正常,但现在我试图实现一个私人消息功能,你基本上输入你朋友的IP和消息,并将其发送到服务器,它能够将消息发送到与该IP相关的特定客户端

我有一切工作,除了我不能弄清楚如何发送文本到一个特定的客户端基于他们的IP地址。我想我可以这样做,其中temp2是一个字符串,msgIP是目标IP, msg是消息:

for I := 1 to ServerSocket1.Socket.ActiveConnections do
begin
  temp2:=ServerSocket1.Socket.Connections[i];
  if temp2=msgIP then
  begin
    ServerSocket1.Socket.Connections[i].SendText(msg);
  end;
end;

你的代码中有三个错误:

  1. Connections[]属性使用基于0的索引,但是您的循环使用基于1的索引。你总是会跳过第一个连接,并且在尝试访问最后一个连接时崩溃。

  2. Connections[]属性返回TCustomWinSocket对象指针,而不是字符串。您需要将目标IP字符串与对象的RemoteAddress属性值进行比较

  3. 如果你找到匹配,你就不会打破循环

试试这个:

var
  client: TCustomWinSocket;
begin
  for I := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    client := ServerSocket1.Socket.Connections[i];
    if client.RemoteAddress = msgIP then
    begin
      client.SendText(msg);
      break;
    end;
  end;
end;

现在,从服务器的角度来看,知道RemoteAddress是远程客户端的IP。如果客户端通过代理或NAT/路由器连接到服务器,则RemoteAddress IP将是代理/NAT的IP,而不是客户端本身。多个客户端可以通过相同的代理/NAT连接,因此它们都具有相同的RemoteAddress IP。如果这只是一个类分配,没有涉及代理/NAT,那么RemoteAddress可能是好的,前提是你的应用程序没有多个实例同时运行在同一台机器上。

要唯一地标识服务器上的特定客户端,而不管它如何连接到服务器,您需要将客户端的RemoteAddress RemotePort属性值一起使用:

var
  client: TCustomWinSocket;
begin
  for I := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    client := ServerSocket1.Socket.Connections[i];
    if (client.RemoteAddress = msgIP) and (client.RemotePort = msgPort) then
    begin
      client.SendText(msg);
      break;
    end;
  end;
end;

然而,当一个客户端想要与另一个客户端通信时,使用IP+Port并不是很直观,特别是当它们不知道彼此的Port值时。

一个更好的选择是让每个客户端使用唯一标识符(例如用户名)登录到服务器。您可以使用客户端的TCustomWinSocket.Data属性来跟踪每个客户端的数据,并根据需要进行比较,例如:

type
  TClientData = record
    UserName: string;
  end;
...
// during login...
var
  ClientData: TClientData;
begin
  New(ClientData);
  ClientData.UserName := ...; // read from the client
  Socket.Data := ClientData;
end;
...
// during logout/disconnect...
var
  ClientData: TClientData;
begin
  ClientData := Socket.Data;
  Socket.Data := nil;
  Dispose(ClientData);
end;
...
// during private messaging
var
  client: TCustomWinSocket;
begin
  for I := 0 to ServerSocket1.Socket.ActiveConnections-1 do
  begin
    client := ServerSocket1.Socket.Connections[i];
    if TClientData(client.Data).UserName = msgUser then
    begin
      client.SendText(msg);
      break;
    end;
  end;
end;

通过这种方式,您可以将消息发送到特定的客户端,而不管它位于何处以及如何连接到服务器。特别是当客户端断开连接并重新连接时,其IP/端口每次连接都会更改。登录标识符将更一致,更容易使用。

最新更新