我正在为我的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
可能是好的,前提是你的应用程序没有多个实例同时运行在同一台机器上。
要唯一地标识服务器上的特定客户端,而不管它如何连接到服务器,您需要将客户端的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/端口每次连接都会更改。登录标识符将更一致,更容易使用。