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

转载于:https://www.cnblogs.com/xieyunc/p/9126543.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
DataSnap是一个用于构建多层架构的工具包,可以帮助开发者构建跨平台的客户端-服务器应用程序。在DataSnap中,多线程例子通常用于处理并发请求和提高服务器端的性能。 一个常见的DataSnap多线程例子是创建一个服务器应用程序,该应用程序可以同时处理多个客户端请求。通过使用多线程,可以让服务器同时处理多个客户端的请求,提高了服务器的处理性能和并发能力。 对于一个简单的DataSnap多线程例子,可以通过以下步骤实现: 1. 创建一个DataSnap服务器应用程序,并添加一个多线程处理模块; 2. 在处理模块中编写多线程代码,以便服务器可以同时处理多个客户端请求; 3. 在客户端应用程序中,编写发送并发请求的代码,并测试服务器的处理能力; 4. 通过监控服务器端的性能数据,如处理请求数、响应时间等指标,来验证多线程处理能力的提高。 另外,DataSnap还提供了一些内置的多线程支持,比如TThreadPool和TTask,开发者可以直接使用这些组件来简化多线程编程,提高开发效率。 总之,DataSnap多线程例子可以帮助开发者学习如何利用多线程来提高服务器端的并发处理能力,从而改善客户端-服务器应用程序的性能和稳定性。同时,通过使用DataSnap内置的多线程支持,开发者可以更加方便地实现多线程编程,提高开发效率。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值