如何在Delphi DataSnap中向指定ID和IP的客户端发送消息?
Delphi DataSnap 指定客户端发送消息时ID不匹配问题解决
问题根源
你获取的DSConnectEventObject.ChannelInfo.Id是DataSnap会话ID,而你尝试用Socket操作时用到的是底层TCP连接的ID,这两个ID属于不同层级的标识,自然无法对应,导致匹配失败。
正确的客户端标识关联方法
要实现向指定ID/IP的客户端发消息,需要把DataSnap会话ID、客户端IP和底层TCP连接信息关联起来:
自定义客户端会话存储结构
在ServerContainer里定义全局存储结构,保存每个客户端的完整信息:type TClientSession = record SessionId: Integer; // DataSnap会话ID(ChannelInfo.Id) ClientIP: string; // 客户端IP地址 TCPTransport: TDSTCPServerTransport; // 对应的TCP传输组件 ConnectionId: Integer; // 底层TCP连接ID end; var ClientSessions: TObjectList<TClientSession>;在ServerContainer的创建/销毁事件中初始化、释放存储:
procedure TServerContainer1.DataModuleCreate(Sender: TObject); begin ClientSessions := TObjectList<TClientSession>.Create(True); end; procedure TServerContainer1.DataModuleDestroy(Sender: TObject); begin ClientSessions.Free; end;连接时记录完整客户端信息
在DSServer1Connect事件中,同时捕获会话ID、客户端IP和TCP连接ID:procedure TServerContainer1.DSServer1Connect(DSConnectEventObject: TDSConnectEventObject); var ClientSession: TClientSession; TCPChannel: TDSTCPChannelInfo; begin // 判断当前连接为TCP传输类型 if DSConnectEventObject.ChannelInfo is TDSTCPChannelInfo then begin TCPChannel := TDSTCPChannelInfo(DSConnectEventObject.ChannelInfo); ClientSession.SessionId := DSConnectEventObject.ChannelInfo.Id; ClientSession.ClientIP := TCPChannel.ClientSocket.Binding.PeerIP; ClientSession.ConnectionId := TCPChannel.ConnectionId; ClientSession.TCPTransport := DSTCPServerTransport1; ClientSessions.Add(ClientSession); // 输出日志 Form1.Memo1.Lines.Add(Format('客户端连接:会话ID=%d,IP=%s,TCP连接ID=%d', [ClientSession.SessionId, ClientSession.ClientIP, ClientSession.ConnectionId])); end; end;断开连接时清理会话记录
在DSServer1Disconnect事件中移除对应会话:procedure TServerContainer1.DSServer1Disconnect(DSConnectEventObject: TDSConnectEventObject); var I: Integer; begin for I := ClientSessions.Count - 1 downto 0 do begin if ClientSessions[I].SessionId = DSConnectEventObject.ChannelInfo.Id then begin ClientSessions.Delete(I); Break; end; end; end;向指定客户端发送消息
根据会话ID或IP找到对应TCP连接,执行消息发送:procedure SendMessageToClient(const TargetSessionId: Integer; const Message: string); var I: Integer; ClientSession: TClientSession; Connection: TDSCustomServerConnection; begin for I := 0 to ClientSessions.Count - 1 do begin ClientSession := ClientSessions[I]; if ClientSession.SessionId = TargetSessionId then begin Connection := ClientSession.TCPTransport.FindConnection(ClientSession.ConnectionId); if Assigned(Connection) then begin // 示例:通过自定义服务类的回调方法发送消息 (Connection.ServerClass as TMyCustomServerClass).SendCustomMessage(Message); end; Break; end; end; end;
注意事项
- 若使用DataSnap的
TDSServerCallback回调机制,建议直接基于DataSnap会话ID操作,无需关心底层Socket ID。 - 操作
ClientSessions时需加临界区保护,避免多线程冲突。
内容的提问来源于stack exchange,提问作者user23198637
相关产品推荐
相关产品推荐

