簡體   English   中英

Delphi:如何將文本發送到連接到服務器套接字的一個特定客戶端,知道其本地IP地址?

[英]Delphi : How to send text to one specific client connected to the server socket knowing their local IP Address?

我正在為我的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並不是很直觀。

更好的選擇是讓每個客戶端使用唯一的標識符(例如用戶名)登錄服務器。 您可以使用客戶端的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 /端口會隨着連接而改變。 登錄標識符將更加一致並且更易於使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM