跟踪代码,发现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不是虚的。
没有评论:
发表评论