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.

xe 最大连接数限制、记录客户连接、心跳的更多相关文章

  1. 第十九篇:不为客户连接创建子进程的并发回射服务器(select实现)

    前言 在此前,我已经介绍了一种并发回射服务器实现.它通过调用fork函数为每个客户请求创建一个子进程.同时,我还为此服务器添加了自动消除僵尸子进程的机制.现在请想想,在客户量非常大的情况下,这种为每个 ...

  2. 不为客户连接创建子进程的并发回射服务器( select实现 )

    前言 在此前,我已经介绍了一种并发回射服务器实现( 点此进入 ).它通过调用fork函数为每个客户请求创建一个子进程.同时,我还为此服务器添加了自动消除僵尸子进程的机制.现在请想想,在客户量非常大的情 ...

  3. [转]Android TCP长连接 心跳机制及实现

    背景知识 智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同 Android系统的推送和iOS的推送有什么区别 几种推送的实现方式 协议 1XMPP简介 2 MQTT简介 3移动端消息 ...

  4. 转 互联网推送服务原理:长连接+心跳机制(MQTT协议)

    http://blog.csdn.net/zhangzeyuaaa/article/details/39028369 目录(?)[-] 无线移动网络的特点 android系统的推送和IOS的推送有什么 ...

  5. 互联网推送服务原理:长连接+心跳机制(MQTT协议)

    互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...

  6. 第二十篇:不为客户连接创建子进程的并发回射服务器(poll实现)

    前言 在上文中,我使用select函数实现了不为客户连接创建子进程的并发回射服务器( 点此进入 ).但其中有个细节确实有点麻烦,那就是还得设置一个client数组用来标记select监听描述符集中被设 ...

  7. 移动互联网消息推送原理:长连接+心跳机制(MQTT协议)

    互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了 ...

  8. vsftp客户连接常见故障现象

    ftp客户连接常见故障现象现象0:> ftp: connect :连接被拒绝原因: 服务没启动解决: # chkconfig vsftpd on<Enter> 现象1:500 OOP ...

  9. 不为客户连接创建子进程的并发回射服务器( poll实现 )

    前言 在上文中,我使用select函数实现了不为客户连接创建子进程的并发回射服务器( 点此进入 ).但其中有个细节确实有点麻烦,那就是还得设置一个client数组用来标记select监听描述符集中被设 ...

随机推荐

  1. UVA 1640 The Counting Problem(按位dp)

    题意:给你整数a.b,问你[a,b]间每个数字分解成单个数字后,0.1.2.3.4.5.6.7.8.9,分别有多少个 题解:首先找到[0,b]与[0,a-1]进行区间减法,接着就只是求[0,x] 对于 ...

  2. SQL中去掉换行符 与空格符

    SELECT B.TradeOrderID AS '二段交易号',B.ZipCode AS '邮编', B.Province AS '省',B.City AS '市',B.District AS '区 ...

  3. 最大字串和问题(Maximum Subarray)

    问题描述: ind the contiguous subarray within an array (containing at least one number) which has the lar ...

  4. TCP中间件_个人方案

    按照功能分类,不管是直接的 insert/delete/update/select语句 还是 调用存储过程,基本的功能 就是 增删改查.又分为两大类: (1).查询(会返回结果集的),(2).非查询( ...

  5. 2012 Multi-University Training Contest 7

    2012 Multi-University Training Contest 7 A.As long as Binbin loves Sangsang B.Dead or alive C.Dragon ...

  6. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [bean.xml]: Invocation of init method failed; nested exception is

    在复制xml文件进行修改的时候,我经常将不小心对原文件进行修改,而导致创建bean出错.报错如下所示: Exception sending context initialized event to l ...

  7. mysql建立索引

    mysql的几种索引http://jingyan.baidu.com/article/da1091fbd166ff027849d687.html

  8. New Concept English three (35)

    27 55 The word justice is usually associated with courts of law. We might say that justice has been ...

  9. CentOS给网站配置Https证书

    1.在腾讯云申请域名的证书 2.配置文件 安装相应模块: yum install mod_ssl openssl 编辑配置文件: cd /etc/httpd/conf.d vi jerryqi.con ...

  10. (十一)java循环结构

    while(循环的条件) {循环的语句} int a = 1; while(a < 5) { System.out.println(a);//1,2,3,4 a++; } System.out. ...