跟踪代码,发现session是可以得到,但是比如我打算枚举session的内容,缺没提供方法了。于是,我使用RTTI的盗窃法子,读取了私有变量
procedure RttiGetPrivateValue(AClass: TClass; AInstance: TObject; FieldName: string; var Value: TObject); var ref: TRttiContext; typ: TRttiType; mthd: TRttiMethod; fld: TRttiField; begin typ := ref.GetType(AClass); fld := typ.GetField(FieldName); //can get private value Value := fld.GetValue(AInstance).AsObject; end; procedure EnumSessionData(const Session: TDSSession); var SessionData: TDSSessionDictionaryData; MetaData: TDictionary可以看到,Session里面对于Tcp,默认的只有两个变量,; MetaObjects: TDictionary ; Key: string; begin RttiGetPrivateValue(TDSSession, Session, 'FSessionData', TObject(SessionData)); RttiGetPrivateValue(TDSSessionDictionaryData, SessionData, 'FMetaData', TObject(MetaData)); RttiGetPrivateValue(TDSSessionDictionaryData, SessionData, 'FMetaObjects', TObject(MetaObjects)); for Key in MetaData.Keys do log.Debug('Sesion[%s] = %s', [Key, MetaData[Key]]); for Key in MetaObjects.Keys do log.Debug('SesionObjects[%s] = %s', [Key, MetaObjects[Key].ClassName]); end; function TdmServer.DSServerTrace(TraceInfo: TDBXTraceInfo): CBRType; var Session: TDSSession; begin log.TrackMethod('TdmServer.DSServerTrace'); Session := TDSSessionManager.GetThreadSession; if Session.ObjectCreator <> nil then log.Debug(Session.ObjectCreator.ClassName); log.Debug(TraceInfo.Message); EnumSessionData(Session); //在这里试着枚举读取一下 Result := cbrUSEDEF; end; 
Sesion[remoteip] = 192.168.101.11 Sesion[communicationprotocol] = tcp/ip 这里的remoteip就是调用者ip了,但是如果想到得到sessioin对应的tunnel的具体socket信息,缺是不能了。 这两个值是在 TDSTCPServerTransport.DoOnConnect里放入的,代码如下
procedure TDSTCPServerTransport.DoOnConnect(AContext: IIPContext);
var
  IndyChannel: TDBXChannel;
  FilterChannel: TDBXFilterSocketChannel;
  Event: TDSTCPConnectEventObject;
begin
  FilterChannel := TDBXFilterSocketChannel.Create(Filters);
  IndyChannel := CreateTcpChannel(AContext);
{$IFNDEF POSIX}
  if CoInitFlags = -1 then
    CoInitializeEx(nil, COINIT_MULTITHREADED)
  else
    CoInitializeEx(nil, CoInitFlags);
{$ENDIF}
  IndyChannel.Open;
  // set the delegate
  FilterChannel.Channel := IndyChannel;
  AContext.Data := FProtocolHandlerFactory.CreateProtocolHandler(FilterChannel);
  if AContext.Data is TDBXJSonServerProtocolHandler then
  begin
    if TDBXJSonServerProtocolHandler(AContext.Data).DSSession = nil then
    begin
      TDBXJSonServerProtocolHandler(AContext.Data).DSSession :=
        TDSSessionManager.Instance.CreateSession(
          function: TDSSession
          begin
            Result := TDSTCPSession.Create(AuthenticationManager);
            Result.PutData('CommunicationProtocol', 'tcp/ip'); //这里放了进去
            Result.PutData('RemoteIP', AContext.Connection.Socket.Binding.PeerIP); //这里放了进去信息
          end,
          ''
        );
    end;
  end;
  if Assigned(FTDSTCPConnectEvent) and (AContext <> nil) and (AContext.Connection <> nil) and
    (FTcpServer <> nil) and FTcpServer.Active then
  begin
    if IndyChannel Is TDSTCPChannel then
    begin
      //enable keep alive, disable it, or leave the OS default setting as it is
      if FKeepAliveEnablement = kaEnabled then
        TDSTCPChannel(IndyChannel).EnableKeepAlive(FKeepAliveTime, FKeepAliveInterval)
      else if FKeepAliveEnablement = kaDisabled then
        TDSTCPChannel(IndyChannel).DisableKeepAlive;
      Event := TDSTCPConnectEventObject.Create(AContext.Connection.GetObject, TDSTCPChannel(IndyChannel));
    end
    else
      Event := TDSTCPConnectEventObject.Create(AContext.Connection.GetObject, nil);
    try
      OnConnect(Event);
    except
    end;
  end;
end;
 
留意一下key的大小写进去的是RmoteIp,出来却变成了remoteip了,所以默认的Session是不关系大小写的,这是因为TDictionary创建是并没指定TStringComparer.Ordinal。目前DataSnap还不支持自定义TDSSessionData的派生,因为TDSSession.CreateSessionData不是虚的。
 
没有评论:
发表评论