Geo*_*rge 0 sockets delphi delphi-2010
我正在通过网络为我的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;
Run Code Online (Sandbox Code Playgroud)
您的代码中有三个错误:
该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;
Run Code Online (Sandbox Code Playgroud)
现在,据说,RemoteAddress从服务器的角度来看,知道远程客户端的IP.如果客户端通过代理或NAT /路由器连接到服务器,则RemoteAddressIP将是代理/ NAT 的IP,而不是客户端本身.多个客户端可以通过相同的代理/ NAT连接,因此它们都具有相同的RemoteAddressIP.如果这只是一个类赋值并且没有涉及代理/ 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;
Run Code Online (Sandbox Code Playgroud)
但是,当一个客户端想要与另一个客户端通信时,使用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;
Run Code Online (Sandbox Code Playgroud)
这样,您可以将消息发送到特定客户端,无论它位于何处以及如何连接到服务器.特别是如果客户端断开连接并重新连接,其IP /端口每个连接都会更改.登录标识符将更加一致且更易于使用.