有三個錯誤在代碼:
的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 /路由器連接到服務器,則IP將是代理/ NAT的IP,而不是客戶端本身。多個客戶端可以通過相同的代理/ NAT連接,因此它們都具有相同的IP。如果這僅僅是一個班級任務,並且沒有涉及代理/ NAT,那麼RemoteAddress
可能沒問題,前提是您沒有同時在同一臺計算機上運行的多個應用程序實例。
爲了唯一識別客戶的服務器上,它是如何連接到服務器regardlesss,您需要使用客戶端的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 +當一個客戶想要與另一個客戶進行通信時,端口不是很直觀,特別是如果他們不知道彼此的端口值。
更好的選擇是讓每個客戶端用唯一標識符(例如用戶名)登錄到服務器。您可以使用客戶端的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 /端口每個連接更改。登錄標識符將更加一致並且更易於使用。