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. 利用ECharts开发的步骤

    引入Echarts的相关库文件,以及自定义的js文件 <script src="${pageContext.request.contextPath}/js/echarts/source ...

  2. java拷贝指定文件夹下的指定文件类型

    例如:把C:\Windows\SysWOW64下的所有dll文件拷贝到C:\Users\Administrator\Desktop\64dll这个目录 package com.xiaostudy.co ...

  3. ubuntu 支持中文

    1.cat /usr/share/i18n/SUPPORTED 说明:查看系统支持的字符集,你需要注意的是支持字符集的格式,如对中文会有以下一些显示(我的系统如此,我不知是否普遍) zh_CN.GB1 ...

  4. Python基础笔记系列四:工具的安装与配置

    本系列教程供个人学习笔记使用,如果您要浏览可能需要其它编程语言基础(如C语言),why?因为我写得烂啊,只有我自己看得懂!! 一开始是没有打算写工具这篇的,后来发现在某些情况下会遇到一些奇怪的问题,这 ...

  5. ng2 学习笔记(二)表单及表单验证

    在上一篇文章中提到了表单,只说了表单的数据绑定,这一篇文章主要讲一下表单验证,为什么把表单单独拿出来学习,主要是因为,表单是商业应用的支柱,我们用它来执行登录.求助.下单.预订机票.安排会议,以及不计 ...

  6. Mac OS X下实现结束占用某特定端口的进程

    ---恢复内容开始--- 1.打开终端,使用如下命令: lsof -i:**** 以上命令中,****代表端口号,我们首先要知道哪个(或哪些)进程占用该端口,比如你可以运行 lsof -i:8000, ...

  7. 腾讯开源手游热更新方案,Unity3D下的Lua编程

    原文:http://www.sohu.com/a/123334175_355140 作者|车雄生 编辑|木环 腾讯最近在开源方面的动作不断:先是微信跨平台基础组件Mars宣布开源,腾讯手游又于近期开源 ...

  8. Python 乘法口诀表

    环境 Anaconda3 Python 3.6, Window 64bit 目的 输出9*9 乘法口诀表 代码 # -*- coding: utf-8 -*- ''' 1*1=1 2*1=2 2*2= ...

  9. element-ui 的el-button组件中添加自定义颜色和图标的实现方法

    这篇文章主要介绍了element-ui 的el-button组件中添加自定义颜色和图标的实现方法,目前的解决方案是:添加一个自定义全局指令,同时在element-ui源码中,加入对应的组件.需要的朋友 ...

  10. 【git】常用命令大全

    Git常用操作命令收集: 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git   后边接仓库文件地址 查看远程仓库:$ gi ...