You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Delphi DataSnap中向指定ID和IP的客户端发送消息?

Delphi DataSnap 指定客户端发送消息时ID不匹配问题解决

问题根源

你获取的DSConnectEventObject.ChannelInfo.Id是DataSnap会话ID,而你尝试用Socket操作时用到的是底层TCP连接的ID,这两个ID属于不同层级的标识,自然无法对应,导致匹配失败。

正确的客户端标识关联方法

要实现向指定ID/IP的客户端发消息,需要把DataSnap会话ID、客户端IP和底层TCP连接信息关联起来:

  1. 自定义客户端会话存储结构
    在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;
    
  2. 连接时记录完整客户端信息
    在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;
    
  3. 断开连接时清理会话记录
    在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;
    
  4. 向指定客户端发送消息
    根据会话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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 06:03:18