2016-08-08 36 views
0

我正在通過網絡爲我的IT課程設計一個基於文本的小型消息傳遞平臺。德爾福:如何發送文本到一個特定的客戶端連接到服務器插座知道他們的本地IP地址?

一切正常,但現在我試圖實現一個私人消息功能,你基本上輸入你的朋友的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; 

回答

5

有三個錯誤在代碼:

  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 /路由器連接到服務器,則IP將是代理/ NAT的IP,而不是客戶端本身。多個客戶端可以通過相同的代理/ NAT連接,因此它們都具有相同的IP。如果這僅僅是一個班級任務,並且沒有涉及代理/ NAT,那麼RemoteAddress可能沒問題,前提是您沒有同時在同一臺計算機上運行的多個應用程序實例。

爲了唯一識別客戶的服務器上,它是如何連接到服務器regardlesss,您需要使用客戶端的RemoteAddressRemotePort屬性值加在一起:但是

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 /端口每個連接更改。登錄標識符將更加一致並且更易於使用。

相關問題