zoukankan      html  css  js  c++  java
  • DataSnap的如果网络断线,如何恢复?

    timer代码很简单:
    var adbsevertime :TDateTime;
    begin
    try
    adbsevertime :=
    ClientModule1.ServerMethods1Client.GetDbServerTime;
    if adbsevertime <> 0 then
    begin
    gdbStatus := true;
    TimerReconnet.Enable:=false;
    end;

    except
    on E: Exception do
    begin

    TimerReconnet.Enable:=true;
    end;
    end;
    end;

    GetDbServerTime是dephi自动生成的客户端访问中间层的方法

    网上找到三种方法:
    http://www.cnblogs.com/yagzh2000/archive/2013/04/27/3046637.html

    http://blog.csdn.net/sunstone/article/details/5023718
    http://blog.163.com/bin0315@126/blog/static/4066264220128414025829/
    类似)


    http://bbs.2ccc.com/topic.asp?topicid=396438

    我每个测试一下,到时候结果通知大家。

    我来说下这一天的成果:
    因为自己很少用datasnap,然后网上对indy有偏见言辞,我抱着这个心态开始实验:

    因为我用的是 datasnap rest 服务,也就是没有用tcp,用的是http,网上的资料对我来说初看没有用。xe2对于tcpconnection设置了心跳包属性,也对我来说无用。
    因为用的是http,用后即关闭,所以心跳包是否有用,我也不清楚。
    怎么办呢?最后我找到TIdHTTPWebBrokerBridge这个实例Fserver里面有个onconnect事件,可以用,于是就手写了事件照猫画虎把delphi2010的代码粘贴下来了,不知道是否用。
    代码如下:
     FServer := TIdHTTPWebBrokerBridge.Create(Self);
      FServer.OnConnect:=ServerConnect;
      FServer.OnDisconnect:=  ServerDisConnect ;

    实现代码:
    procedure TForm1.ServerConnect(AContext: TIdContext);
    var
      Val: TCP_KeepAlive;
      Ret: DWORD;
      conne: tidtcpconnection;
      aip, aport, ausername, apass: string;
    begin
     //验证
      conne := TIdTCPConnection(AContext.Connection);
      if conne <> nil then
      begin
        aip := conne.Socket.Binding.PeerIP;
        aport := inttostr(conne.Socket.Binding.PeerPort);
    //  ausername := DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName];
    //  apass := DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
    //  if (ausername <> 'jiangbin') and (apass <> '2010') then
    //    DSConnectEventObject.DbxConnection.Destroy
    //  else
    //    fr_main.memo1.Lines.add(aip + ':' + aport + '  名称:' + ausername);

    //心跳包代码
        Val.OnOff := 1;
        Val.KeepAliveTime := 5000;
        Val.KeepAliveInterval := 3000;
        WSAIoctl(conne.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or 4, @Val,
          SizeOf(Val), nil, 0, @Ret, nil, nil);
      end;

    end;



    procedure TForm1.ServerDisConnect(AContext: TIdContext);
    var
      conne: tidtcpconnection;
      aip, aport, ausername, apass: string;
      i: integer;
    begin
    //断开后清除连接IP及端口


      conne := TIdTCPConnection(AContext.Connection);
      if conne <> nil then
      begin
        aip := conne.Socket.Binding.PeerIP;
        aport := IntToStr(conne.Socket.Binding.PeerPort);
      end;

    end;

    但是不知道是否有用,待测。

    另外,我在调试过程中,发现indy并不是想象的那么差,很完善
    其实delphi事实是调用tidhttp 完成rest服务的,只是我这边有个问题,就是如果断线,调用异常,再次调用服务,就会出现服务器的index of bounds越界错误,(主要是构建http头,出现异常),这个应该是一个Indy bug吧,所以我准备临界来处理datasnap的中间层请求,保证异常后,不能同时再被访问,这样就可以了。

    解决如果出现HTTP/1.1 403 Session has expired,datasnap不能重连功能,刚开始如果客户端正常连接中间层,然后中间层杀掉 ,客户端由于是用老的session去连接中间层,会被重新启动的中间层认为session过期。所以一直是返回raise,无限期不能重连。
    解决方案,出现session错误时,把sessionid清空。

    我发现问题跟tidhttp一毛钱关系没有,说明indy代码还是很不错的啊:)只是datasnap的代码未考虑异常。


    解决如下:找到delphi源代码DSClientRest文件,复制到你的项目文件夹中,找到

    procedure ExecuteCommand(ACommand: TDSRestCommand; const ARequestFilter, AAccept: string); overload;


    把原先的1129行
    ExecuteRequest(ACommand.Connection.HTTP, LURL, ACommand.RequestType, ACommand.Connection.LoginProperties.UserName, ACommand.Connection.LoginProperties.Password, ACommand.Parameters, ARequestFilter, AAccept,
        LSessionID,
        procedure
        begin
          ACommand.Connection.SessionExpired;
        end,
        procedure(ASessionID: string)
        begin
          if ASessionID <> '' then
            ACommand.Connection.SessionID := ASessionID;
        end);

    改为:

     try
      ExecuteRequest(ACommand.Connection.HTTP, LURL, ACommand.RequestType, ACommand.Connection.LoginProperties.UserName, ACommand.Connection.LoginProperties.Password, ACommand.Parameters, ARequestFilter, AAccept,
        LSessionID,
        procedure
        begin
          ACommand.Connection.SessionExpired;
        end,
        procedure(ASessionID: string)
        begin
          if ASessionID <> '' then
            ACommand.Connection.SessionID := ASessionID;
        end);
      except

       on E:Exception do
       begin
         if Pos('Session has expired',E.Message)>0 then
         begin
          ACommand.Connection.SessionID:='';
         end;
         raise;
       end;

      end;


    既可,这样,重连中间层可以实现了。

    经过二个多月对于datasnap的一个项目学习,发现emb的人喜欢把程序员当做刚做程序的小白,所以代码很完善,让你很简单就建立了一个rest 服务(内部细节都由emb帮助你做好了)。但是他们处于实验室阶段,有时候没有考虑真实环境的差异,特别是一些异常未做处理。也就是说 有些坑需要你自己去填,但是填完后,发现datasnap还是不错的。:-)

    http://bbs.2ccc.com/topic.asp?topicid=524327

  • 相关阅读:
    第十一周编程总结
    第十一周助教总结
    第十周编程总结
    第十周学习总结
    第十周助教总结
    第九周学习总结
    第九周编程总结
    第九周助教总结
    第八周学习总结
    第八周编程总结
  • 原文地址:https://www.cnblogs.com/findumars/p/6491478.html
Copyright © 2011-2022 走看看