zoukankan      html  css  js  c++  java
  • DataSnap Demo:TFDConnection、最大连接数、客户端回叫功能、多线程模拟、压力测试等

    一、限制最大连接数,并验证来访者用户身份:

    procedure TServerContainer1.DSServer1Connect(
      DSConnectEventObject: TDSConnectEventObject);
    var
      sError:string;
    begin
      //限制最大连接数,并且验证来访者密码
      if (DSConnectEventObject.ChannelInfo = nil)
         or (FConnections.Count > _MaxConnCount)
         or (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName] <> _UserName)
         or (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password] <> _UserPassWord)
         //or (DSConnectEventObject.ChannelInfo.ClientInfo.IpAddress)<>'127.0.0.1')
         then
      begin
      try
        //客户端调用RegisterCallback或UnRegisterCallback方法时,_UserName和_UserPassWord将赋值给
        //TDBXPropertyNames.DSAuthenticationUser和TDBXPropertyNames.DSAuthenticationPassword这两个属性,
        //而真正的TDBXPropertyNames.UserName和TDBXPropertyNames.Password属性反而没有被赋值,不知道这算不算XE的一个BUG。
        //本人已修正这一“BUG”,在Datasnap.DSCommon.pas单元的第484行附近的这一函数:
        //function TDSClientCallbackChannelManager.DBXConnectionProperties(NoTimeout: Boolean): TDBXDatasnapProperties;
        //中,加上了对TDBXPropertyNames.UserName和TDBXPropertyNames.Password属性的赋值,此单元源文件我放在Demo目录下了。
        //必须加上此判断,因为注销回叫函数时会新开一个连接测试服务器是否可用,如果不加上此判断,当客户端连接数正好达到
        //我们设置的最大连接数时,因再无连接数可用会导致回叫函数一直无法被注销。
        if (DSConnectEventObject.ChannelInfo <> nil) and
           (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.DSAuthenticationUser] = _UserName) and
           (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.DSAuthenticationPassword] = _UserPassWord) then
           Exit;
    
        if (FConnections.Count > _MaxConnCount) then
        begin
          sError := '客户端超过服务器的最大连接数了!'
        end
        else if (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName]<>_UserName) or
                (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password]<>_UserPassWord) then
          sError := '认证失败!非法的接入用户,连接被拒绝!'
        else
          sError := '';
        DSConnectEventObject.DbxConnection.Destroy;
      except
        on e:Exception do
        begin
          if sError<>'' then
            raise Exception.Create(sError)
          else
            raise e;
        end;
      end;
      end;
    end;

    二、最大连接数的设定

    procedure TSrvMainForm.InitDSServerOpt;
    begin
      _MaxConnCount := StrToIntDef(edt_MaxCount.Text,0);
      ServerContainer1.DSTCPServerTransport1.MaxThreads := _MaxConnCount+5;
      _UserName := edt_UserName.Text;
      _UserPassWord := edt_UserPwd.Text;
      //千万别设置MaxThreads属性,如果设置此属性,一旦客户端连接数超此值,服务器并不会向客户端反馈任何消息,
      //而是把客户端连接请求放入队列中,一直等到直至服务器有空闲、断开或者其他原因得到的“可用的”连接资源,
      //从而导致客户端进入假死状态。
      //ServerContainer1.DSTCPServerTransport1.MaxThreads := _MaxConnCount;
    end;
    
    三、动态注册回叫控件
    procedure TClientMainForm.btn_RegCallback_DynClick(Sender: TObject);
    var
      i:integer;
      se:Cardinal;
      sManagerId,sCallbackId:string;
    begin
      se := GetTickCount;
      edt_SecondLength.Text := '';
      Memo1.Lines.Clear;
      Application.ProcessMessages;
    
      Screen.Cursor := crHourGlass;
      try
        FarrCount := StrToIntDef(edt_CallbackCount.Text,1);
        btn_UnRegCallback_DynClick(Self);
        SetLength(arrChannelManager,FarrCount);
    
        for i := Low(arrChannelManager) to High(arrChannelManager) do
        begin
          sCallbackId := Format('%.4d',[i+1]); //IntToStr(GetTickCount());//'XXX-LMM';
          sManagerId := '客户端_'+sCallbackId;
          if not Assigned(arrChannelManager[i]) then
            arrChannelManager[i] := TDSClientCallbackChannelManager.Create(nil)
          else
            arrChannelManager[i].UnregisterCallback(sCallbackId);
    
          arrChannelManager[i].ChannelName := 'jfglxt'; //可以把应用程序标识存放于此
          arrChannelManager[i].ManagerId := sManagerId;
          arrChannelManager[i].CommunicationProtocol := 'tcp/ip';
          arrChannelManager[i].DSHostname := edt_SrvIp.Text;
          arrChannelManager[i].DSPort := '211';
          arrChannelManager[i].UserName := edt_UserName.Text;
          arrChannelManager[i].Password := edt_UserPwd.Text;
    
          arrChannelManager[i].RegisterCallback(sCallbackId,TDemoCallback.Create);
          edt_CallbackCount.Text := IntToStr(i+1);
          Application.ProcessMessages;
        end;
      finally
        edt_SecondLength.Text := Format('%fs',[(gettickcount()-se)/1000]);
        Screen.Cursor := crDefault;
      end;
    end;
    
    四、创建多个线程,对数据库进行查询

    procedure TClientMainForm.btn_RegCallback_DynClick(Sender: TObject);
    var
      i:integer;
      se:Cardinal;
      sManagerId,sCallbackId:string;
    begin
      se := GetTickCount;
      edt_SecondLength.Text := '';
      Memo1.Lines.Clear;
      Application.ProcessMessages;
    
      Screen.Cursor := crHourGlass;
      try
        FarrCount := StrToIntDef(edt_CallbackCount.Text,1);
        btn_UnRegCallback_DynClick(Self);
        SetLength(arrChannelManager,FarrCount);
    
        for i := Low(arrChannelManager) to High(arrChannelManager) do
        begin
          sCallbackId := Format('%.4d',[i+1]); //IntToStr(GetTickCount());//'XXX-LMM';
          sManagerId := '客户端_'+sCallbackId;
          if not Assigned(arrChannelManager[i]) then
            arrChannelManager[i] := TDSClientCallbackChannelManager.Create(nil)
          else
            arrChannelManager[i].UnregisterCallback(sCallbackId);
    
          arrChannelManager[i].ChannelName := 'jfglxt'; //可以把应用程序标识存放于此
          arrChannelManager[i].ManagerId := sManagerId;
          arrChannelManager[i].CommunicationProtocol := 'tcp/ip';
          arrChannelManager[i].DSHostname := edt_SrvIp.Text;
          arrChannelManager[i].DSPort := '211';
          arrChannelManager[i].UserName := edt_UserName.Text;
          arrChannelManager[i].Password := edt_UserPwd.Text;
    
          arrChannelManager[i].RegisterCallback(sCallbackId,TDemoCallback.Create);
          edt_CallbackCount.Text := IntToStr(i+1);
          Application.ProcessMessages;
        end;
      finally
        edt_SecondLength.Text := Format('%fs',[(gettickcount()-se)/1000]);
        Screen.Cursor := crDefault;
      end;
    end;

    截个图:

    源码下载:

    DataSanpDemo.rar

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    Coursera Algorithm II PA2 Q2
    Coursera Algorithm Part II PA2
    实现 memcpy 函数
    超人
    Proxy 模式
    【6】锋利的 jQuery 笔记
    【3】Chrome 的一些常用操作
    HTML 待解决与已解决问题
    CSS 待解决问题
    JS 一些常用技巧
  • 原文地址:https://www.cnblogs.com/xieyunc/p/4839595.html
Copyright © 2011-2022 走看看