• xe 最大连接数限制、记录客户连接、心跳


    //author: cxg

    unit DSServerContainer;

    interface

    uses
      SysUtils, Classes, IniFiles, Windows, Provider, DBClient,
      DSTCPServerTransport,
      DSServer, DSCommonServer, DB, ADODB, Generics.Collections, DSService,
      DBXDataSnap, DBXCommon, DSHTTPLayer, DBXinterbase, forms, DbxCompressionFilter
      ,IdTCPConnection ,IdWinsock2, ExtCtrls
      ;

    type
      TTCP_KeepAlive = record
        OnOff: Cardinal;
        KeepAliveTime: Cardinal;     // 多长时间(ms)没有数据就开始send心跳包
        KeepAliveInterval: Cardinal; // 每隔多长时间(ms)send一个心跳包,发5次(系统值)
      end;

      TServerContainer1 = class(TDataModule)
        DSServer1: TDSServer;
        DSTCPServerTransport1: TDSTCPServerTransport;
        DSServerClass1: TDSServerClass;
        procedure DSServerClass1GetClass(DSServerClass: TDSServerClass;
          var PersistentClass: TPersistentClass);
        procedure DataModuleCreate(Sender: TObject);
        procedure DSServer1Disconnect(DSConnectEventObject: TDSConnectEventObject);
        procedure DSServer1Connect(DSConnectEventObject: TDSConnectEventObject);
      private
        { Private declarations }

      end;

    var
      ServerContainer1: TServerContainer1;
     

    implementation

    uses  ServerMethodsUnit1,MainForm;

    {$R *.dfm}

    procedure TServerContainer1.DataModuleCreate(Sender: TObject);
    begin
      DSServer1.AutoStart :=False;
      DSTCPServerTransport1.Port :=g_port;
      DSServer1.Start;
    end;

    procedure TServerContainer1.DSServer1Connect(
      DSConnectEventObject: TDSConnectEventObject);
    var
      ClientConnection: TIdTCPConnection;
      Val: TTCP_KeepAlive;
      Ret: DWord;
    begin
      // 最大连接数量限制,验证来访者密码
      if (DSConnectEventObject.ChannelInfo = nil) or
        (g_CurrentConnNum >= FrmMain.MaxclientNum) or
        (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName] <> g_username) or
        (DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password] <> g_userpassword) then
      begin
        DSConnectEventObject.DbxConnection.Destroy;
        Exit;
      end
      else
      begin
        inc(g_currentconnnum);  // 记录来访者数量
        //把心跳包放到服务端上执行,如果服务器的某个TCP连接在5秒钟没有收到数据,
        //将会发送向对端发送心跳包,间隔3秒钟,连续发送5次。如果5次以后对端还没有应答,服务器将结束该TCP连接
        ClientConnection := TIdTCPConnection(DSConnectEventObject.ChannelInfo.Id);
        Val.OnOff := 1;
        Val.KeepAliveTime := 5000;
        Val.KeepAliveInterval := 3000;
        WSAIoctl(ClientConnection.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or 4,
          @val, SizeOf(val), nil, 0, @Ret, nil, nil);
      end;

      //记录客户连接
      with FrmMain do
      begin
        dsShowDataSet.Append;
        dsShowDataSet.FindField('ClientConnect').AsDateTime := Time;

        if DSConnectEventObject.ChannelInfo <> nil then
        begin

          dsShowDataSet.FindField('ClientId').AsInteger := DSConnectEventObject.ChannelInfo.Id;
          dsShowDataSet.FindField('ClientIp').AsString := ClientConnection.Socket.Binding.PeerIP +
            ':' + IntToStr(ClientConnection.Socket.Binding.PeerPort);
          dsShowDataSet.FindField('ServerIp').AsString := ClientConnection.Socket.Binding.IP + ':' +
            IntToStr(ClientConnection.Socket.Binding.Port);
        end;

        dsShowDataSet.FindField('ClientUserName').AsString := DSConnectEventObject.ConnectProperties
          [TDBXPropertyNames.UserName];
        dsShowDataSet.FindField('ClientUserPassword').AsString :=
          DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
        dsShowDataSet.FindField('ServerInfo').AsString := '上线';
        dsShowDataSet.Post;
      end;
    end;

    procedure TServerContainer1.DSServer1Disconnect(
      DSConnectEventObject: TDSConnectEventObject);
    var
      ClientConnection: TIdTCPConnection;
    begin
      //记录客户下线
      with FrmMain do
      begin
        dsShowDataSet.Append;
        dsShowDataSet.FindField('ClientDisConn').AsDateTime := Time;

        if DSConnectEventObject.ChannelInfo <> nil then
        begin
          ClientConnection := TIdTCPConnection(DSConnectEventObject.ChannelInfo.Id);
          dsShowDataSet.FindField('ClientId').AsInteger := DSConnectEventObject.ChannelInfo.Id;
          dsShowDataSet.FindField('ClientIp').AsString := ClientConnection.Socket.Binding.PeerIP +
            ':' + IntToStr(ClientConnection.Socket.Binding.PeerPort);
          dsShowDataSet.FindField('ServerIp').AsString := ClientConnection.Socket.Binding.IP + ':' +
            IntToStr(ClientConnection.Socket.Binding.Port);
        end;

        dsShowDataSet.FindField('ClientUserName').AsString := DSConnectEventObject.ConnectProperties
          [TDBXPropertyNames.UserName];
        dsShowDataSet.FindField('ClientUserPassword').AsString :=
          DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
        dsShowDataSet.FindField('ServerInfo').AsString := '下线';
        dsShowDataSet.Post;
      end;

      Dec(g_CurrentConnNum);
    end;

    procedure TServerContainer1.DSServerClass1GetClass(
      DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
    begin
      PersistentClass := ServerMethodsUnit1.TServerMethods1;
    end;

    end.

  • 相关阅读:
    进阶之路 | 奇妙的Drawable之旅
    进阶之路 | 奇妙的Animation之旅
    进阶之路 | 奇妙的四大组件之旅
    Laravel
    Laravel 入门
    面试:给我说说你平时是如何优化MySQL的?
    EXPLAIN 查看 SQL 执行计划
    常见的图文布局
    常见的图文布局
    CSS3 的 filter(滤镜) 属性
  • 原文地址:https://www.cnblogs.com/fhweixin/p/13743031.html
Copyright © 2020-2023  润新知