Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets Delphi:如何向连接到服务器套接字的特定客户端发送文本,并知道其本地IP地址?_Sockets_Delphi_Delphi 2010 - Fatal编程技术网

Sockets Delphi:如何向连接到服务器套接字的特定客户端发送文本,并知道其本地IP地址?

Sockets Delphi:如何向连接到服务器套接字的特定客户端发送文本,并知道其本地IP地址?,sockets,delphi,delphi-2010,Sockets,Delphi,Delphi 2010,我正在为我的IT课程开发一个基于网络的小型短信平台 一切都正常,但现在我正在尝试实现一个私有消息功能,您可以在其中输入朋友的IP和消息,然后将其发送到服务器,服务器可以将消息发送到与该IP相关的特定客户端 我的一切都正常,只是我不知道如何根据一个特定的客户端的IP地址向其发送文本。我想我可以这样做,temp2是一个字符串,msgIP是目标IP,msg是消息: for I := 1 to ServerSocket1.Socket.ActiveConnections do begin temp2

我正在为我的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;

代码中有三个错误:

  • Connections[]
    属性使用基于0的索引,但您的循环使用基于1的索引。您将始终跳过第一个连接,并在试图访问最后一个连接时崩溃

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

  • 如果你找到匹配的,你就不会打破循环

  • 请尝试以下方法:

    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
    就可以了,前提是您的应用程序没有多个实例同时在同一台机器上运行

    要唯一标识服务器上的特定客户端,不考虑其与服务器的连接方式,您需要同时使用客户端的
    远程地址
    远程端口
    属性值:

    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+端口不是很直观,特别是当他们不知道彼此的端口值时

    更好的选择是让每个客户端使用唯一标识符(如用户名)登录到服务器。您可以使用客户端的
    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/端口在每次连接时都会发生变化。登录标识符将更加一致,更易于使用。

    您的代码中有三个错误:

  • Connections[]
    属性使用基于0的索引,但您的循环使用基于1的索引。您将始终跳过第一个连接,并在试图访问最后一个连接时崩溃

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

  • 如果你找到匹配的,你就不会打破循环

  • 请尝试以下方法:

    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
    就可以了,前提是您的应用程序没有多个实例同时在同一台机器上运行

    要唯一标识服务器上的特定客户端,不考虑其与服务器的连接方式,您需要同时使用客户端的
    远程地址
    远程端口
    属性值:

    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+端口不是很直观,特别是当他们不知道彼此的端口值时

    更好的选择是让每个客户端使用唯一标识符(如用户名)登录到服务器。您可以使用客户端的
    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/端口在每次连接时都会发生变化。登录标识符将更加一致,更易于使用