Sockets Delphi:如何向连接到服务器套接字的特定客户端发送文本,并知道其本地IP地址?
我正在为我的IT课程开发一个基于网络的小型短信平台 一切都正常,但现在我正在尝试实现一个私有消息功能,您可以在其中输入朋友的IP和消息,然后将其发送到服务器,服务器可以将消息发送到与该IP相关的特定客户端 我的一切都正常,只是我不知道如何根据一个特定的客户端的IP地址向其发送文本。我想我可以这样做,Sockets Delphi:如何向连接到服务器套接字的特定客户端发送文本,并知道其本地IP地址?,sockets,delphi,delphi-2010,Sockets,Delphi,Delphi 2010,我正在为我的IT课程开发一个基于网络的小型短信平台 一切都正常,但现在我正在尝试实现一个私有消息功能,您可以在其中输入朋友的IP和消息,然后将其发送到服务器,服务器可以将消息发送到与该IP相关的特定客户端 我的一切都正常,只是我不知道如何根据一个特定的客户端的IP地址向其发送文本。我想我可以这样做,temp2是一个字符串,msgIP是目标IP,msg是消息: for I := 1 to ServerSocket1.Socket.ActiveConnections do begin temp2
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
就可以了,前提是您的应用程序没有多个实例同时在同一台机器上运行
要唯一标识服务器上的特定客户端,不考虑其与服务器的连接方式,您需要同时使用客户端的远程地址
和远程端口
属性值:
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/端口在每次连接时都会发生变化。登录标识符将更加一致,更易于使用。您的代码中有三个错误:
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
就可以了,前提是您的应用程序没有多个实例同时在同一台机器上运行
要唯一标识服务器上的特定客户端,不考虑其与服务器的连接方式,您需要同时使用客户端的远程地址
和远程端口
属性值:
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/端口在每次连接时都会发生变化。登录标识符将更加一致,更易于使用