delphi3层 delphi 3层
一、为DataSnap系统服务程序添加描述
procedure TServerContainer.ServiceAfterInstall(Sender: TService);
var
reg: TRegistry;
begin
reg := TRegistry.Create;
try
with reg do
begin
RootKey := HKEY_LOCAL_MACHINE;
if OpenKey('SYSTEM/CurrentControlSet/Services/' + Self.Name, false) then
begin
WriteString('Description', '机房管理系统核心服务');
end;
CloseKey;
end;
finally
reg.Free;
end;
end;
二、DataSnap服务端和客户端发布分发方法
服务器发布方法:
1.在unit ServerMethodsUnit1单元中,添加uses MidasLib;(添加MidasLib的目的是省去发布Midas.dll)
2.如果用的是火鸟数据库,只需拷贝dbxfb.dll和fbclient.dll,如果用的是SQLite,则什么都不用拷贝。
分发的服务器软件只需三个文件:你的服务器程序、dbxfb.dll 和 fbclient.dll
客户端发布方法:
1.在客户端程序中加上uses MidasLib;(添加MidasLib的目的是省去发布Midas.dll)
2.如果服务器使用了http协议作为DataSnap通讯的话,还需在客户端程序中加上users DSHTTPLayer,如果使用tcp协议,无需此步骤。
服务器和客户端无需Midas.dll,也不需要注册regsvr32 Midas.dll,看来Delphi2010的datasnap抛弃使用COM真是进步不少!
另外,通过研究发现,DSConnectEventObject.ChannelInfo.Id属性实际上是内存地址,并不是一个简单的数字。
uses IdTCPConnection;
//......
procedure TServerContainer1.DSServer1Connect(DSConnectEventObject: TDSConnectEventObject);
var
ClientConnection: TIdTCPConnection;
begin
with Form1 do
begin
dsShowDataSet.Append;
dsShowDataSet['ClientConnectTime'] := Now;
if DSConnectEventObject.ChannelInfo <> nil then
begin
ClientConnection := TIdTCPConnection(DSConnectEventObject.ChannelInfo.Id);
dsShowDataSet['ClientID'] := DSConnectEventObject.ChannelInfo.Id;
dsShowDataSet['ClientIP'] := ClientConnection.Socket.Binding.PeerIP +
':' + IntToStr(ClientConnection.Socket.Binding.PeerPort);
dsShowDataSet['ServerIP'] := ClientConnection.Socket.Binding.IP + ':' +
IntToStr(ClientConnection.Socket.Binding.Port);
end;
dsShowDataSet['ClientUserName'] := DSConnectEventObject.ConnectProperties
[TDBXPropertyNames.UserName];
dsShowDataSet['ClientUserPassword'] :=
DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
dsShowDataSet['ServerInfo'] := DSConnectEventObject.ConnectProperties
[TDBXPropertyNames.ServerConnection];
dsShowDataSet.Post;
end;
end;
或者也可以这样:
procedure TServerContainer1.DSServer1Connect(DSConnectEventObject: TDSConnectEventObject);
var
ClientConnection: TDBXClientInfo;
Val: TTCP_KeepAlive;
Ret: DWord;
begin
ClientConnection := DSConnectEventObject.ChannelInfo.ClientInfo;
AddLog(
ClientConnection.IpAddress
+':'+
ClientConnection.ClientPort
+'登录服务器');
UpdateLinkToList(ClientConnection.IpAddress
+':'+
ClientConnection.ClientPort
,IntToStr(DSConnectEventObject.ChannelInfo.Id)
,0);
end;
四、DataSnap中的TCP keepAlive和KeepAliveInterval(心跳包)参数详解
大家先了解一下 TCP keep-alive原理
一个TCP keep-alive 包是一个简单的ACK,该ACK包内容为一个比当前连接sequence number 小于一的包。主机接受到这些ACKs会返
回一个包含当前sequence number 的ACK包。
Keep-alives一般被用来验证远端连接是否有效。如果该连接上没有其他数据被传输,或者更高level 的 keep-alives被传送,keep-alives 在每个KeepAliveTime被发送。(默认是 7,200,000 milliseconds ,也就是2个小时)。
如果没有收到 keep-alive 应答,keep-alive 将在每 KeepAliveInterval 秒重发一次。KeepAliveInterval 默认为1秒。如 Microsoft 网络功能中很多部分中采用的 NETBT 连接,更常见的是发送 NETBios keep-alives,所以,在 NetBios 连接中通常不发送TCP keep-alives。
TCP保持连接默认被禁用,但是微软Sockets应用程序可以使用SetSockOpt函数去启用他们。
请看下面的类
复制代码
type
TCP_KeepAlive = record
OnOff: Cardinal;
KeepAliveTime: Cardinal; // 多长时间(ms)没有数据就开始send心跳包
KeepAliveInterval: Cardinal // 每隔多长时间(ms)send一个心跳包,发5次(系统值)
end;
复制代码
KeepAliveTime: TCP连接多长时间(毫秒)没有数据就开始发送心跳包,有数据传递的时候不发送心跳包
KeepAliveInterval: 每隔多长时间(毫秒)发送一个心跳包,发5次(系统默认值)
如果客户端网络中断,服务器系统发送心跳包后,服务器会自动解除TCP连接。这一点,大家可以使用 netstat -p -tcp 命令查看
接下来我们将结合Delphi2010 DataSnap技术使用心跳包功能!敬请关注
五、建立稳定服务程序之TCP心跳包的使用
为了能让我们的服务程序更加稳定,有些细节问题必须解决。就如上一讲中提到的客户端拔掉网线,造成服务器上TCP变成死连接,如果死连接数量过多,对服务器能长期稳定运行是一个巨大的威胁。
另外,经过测试,如果服务器上有TCP死连接,那么服务程序连接数据库,也会产生那个一个死连接。这样的话,给数据库服务器也造成威胁。所以,服务器程序编写的好坏,直接影响系统的稳定性!
如何解决TCP死连接的问题,有多种方法,其中最有效的就是心跳包技术。
我们在DSServer的OnConnect事件中加入心跳包代码
复制代码
uses IdTCPConnection,IdWinsock2
//........
type
TCP_KeepAlive = record
OnOff: Cardinal;
KeepAliveTime: Cardinal;
KeepAliveInterval: Cardinal;
end;
//........
procedure TServerContainer1.DSServer1Connect
(DSConnectEventObject: TDSConnectEventObject);
var
Val: TCP_KeepAlive;
Ret: DWord;
ClientConnection: TIdTCPConnection;
begin
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;
当该TCP结束后,delphi编写的服务程序会自动结束和数据库的连接。我用的是FireBird数据库,大家可以使用命令查看
SELECT MON$USER, MON$REMOTE_ADDRESS,
MON$REMOTE_PID,
MON$TIMESTAMP
FROM MON$ATTACHMENTS
在客户端的SQLConnection1中Driver分类的username和password属性设置好用户名和密码。
3)尽量不要设置DSTCPServerTransport1的Maxthreads属性,还有数据库连接池也不要设置,delphi2010会有内存泄露,这两个参数保存默认即可。
在DSServer1控件的OnConnect事件中加入如下代码(使用的是tcp/ip连接):
复制代码
procedure TMainForm.DSServer1Connect
(DSConnectEventObject: TDSConnectEventObject);
var
val: TCP_KeepAlive;
Ret: Integer;
ClientConnection: TIdTCPConnection;
begin
// 最大连接数量,验证来访者密码
if (DSConnectEventObject.ChannelInfo = nil) or (Connections >= 500) or
(DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName]
<> 'sunstone') or (DSConnectEventObject.ConnectProperties
[TDBXPropertyNames.Password] <> 'mypassword') then
begin
DSConnectEventObject.DbxConnection.Destroy;
// ClientConnection.Disconnect;
end
else
begin
// 获取socket连接
ClientConnection := TIdTCPConnection(DSConnectEventObject.ChannelInfo.Id);
ClientConnection.OnDisconnected := ClientDisconnectEvent;
// 记录来访者数量
inc(Connections);
lblShowConnections.Caption := IntToStr(Connections);
if Trim(ShowConnections.Cells[0, 1]) <> '' then
ShowConnections.RowCount := ShowConnections.RowCount + 1;
ShowConnections.Cells[0, ShowConnections.RowCount - 1] := IntToStr
(DSConnectEventObject.ChannelInfo.Id);
ShowConnections.Cells[1, ShowConnections.RowCount - 1] :=
ClientConnection.Socket.Binding.PeerIP + ':' + IntToStr
(ClientConnection.Socket.Binding.PeerPort);
ShowConnections.Cells[2, ShowConnections.RowCount - 1] :=
DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName];
ShowConnections.Cells[3, ShowConnections.RowCount - 1] :=
DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
ShowConnections.Cells[4, ShowConnections.RowCount - 1] := FormatDateTime
('yyyy-mm-dd hh:nn:ss', Now);
// ShowConnections.Cells[6, ShowConnections.RowCount - 1] :=
// DSConnectEventObject.ConnectProperties
// [TDBXPropertyNames.ServerConnection];
// 设置心跳包
val.OnOff := 1;
val.KeepAliveTime := 5000;
val.KeepAliveInterval := 1000;
WSAIoctl(ClientConnection.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or 4,
@val, SizeOf(val), nil, 0, @Ret, nil, nil);
end;
end;
相关文章:
delphi3层 delphi 3层
一、为DataSnap系统服务程序添加描述 procedure TServerContainer.ServiceAfterInstall(Sender: TService); var reg: TRegistry; begin reg : TRegistry.Create; try with reg do begin RootKey : HKEY_LOCAL_MACHINE; if OpenKey(SYSTEM/CurrentC…...
Python编程学习第一篇——制作一个小游戏休闲一下
到上期结束,我们已经学习了Python语言的基本数据结构,除了数值型没有介绍,数值型用的非常广,但也是最容易理解的,将在未来的学习中带大家直接接触和学习掌握。后续我们会开始学习这门语言的一些基础语法和编程技巧&…...
03--nginx架构实战
前言:这应该是nginx梳理的最后一章,写一些关于网站架构和网站上线的知识内容,主要是感觉到运维并不是单一方向的行业,这一章概念会有一些广泛,但是非常重要,都是这几年工作中遇到的情况,整理一下…...
【力扣第 400 场周赛】Leetcode 删除星号以后字典序最小的字符串
文章目录 1. 删除星号以后字典序最小的字符串 1. 删除星号以后字典序最小的字符串 题目链接 🍎 解题思路:遇到 *就删除一个字符,为了满足题意,要删除字典序最小的字符,那么假如有多个字典序最小的字符我们该删除哪个…...
Unity DOTS技术(九) BufferElement动态缓冲区组件
文章目录 一.简介二.例子 一.简介 在之前的学习中我们发现Entity不能挂载相同的组件的. 当我们需要用相同的组件时则可以使用.IBufferElementData接口 动态缓冲区组件来实现 二.例子 1.创建IBufferElementData组件 using Unity.Entities; using UnityEngine; //[GenerateAu…...
hnust 湖南科技大学 2022 软件测试报告+代码
hnust 湖南科技大学 2022 软件测试报告代码 内容 BMI junit单元测试决策表划分方法测试三角形判断问题文档修改问题之因果图实验逻辑覆盖测试技术实验(白盒测试)selenium 功能自动化测试Jmeter 性能自动化测试 下载地址 https://pan.baidu.com/s/19e…...
【面试笔记】单片机软件工程师,工业控制方向(储能)
文章目录 1. 基础知识1.1 C语言笔试题1.1.1 用宏定义得到一个数组所含的元素个数1.1.2 定义函数指针从程序固定地址(0)开始执行1.1.3 volatile的含义及作用1.1.4 32位系统,整数7和-7,分别以大端和小端存储,请示意说明 1.2 嵌入式基础1.2.1 简…...
基于springboot实现小区团购管理系统项目【项目源码+论文说明】计算机毕业设计
基于springboot实现小区团购管理系统演示 摘要 传统办法管理信息首先需要花费的时间比较多,其次数据出错率比较高,而且对错误的数据进行更改也比较困难,最后,检索数据费事费力。因此,在计算机上安装小区团购管理软件来…...
基于django | 创建数据库,实现增、删、查的功能
1、在cmd中,输入指令进入mysql终端: mysql -u 用户名 -p 2、输入mysql的密码 3、输入指令,显示出所有的数据库 show databases; 4、输入指令创建表: create table 表名 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 5、use …...
数据结构与算法07-图
介绍 图是一种善于处理关系型数据的数据结构,使用它可以很轻松地表示数据之间是如何关联的。 图的实现形式有很多,最简单的方法之一就是用散列表。 friends { "Alice" > ["Bob", "Diana", "Fred"], &quo…...
springboot项目部署需要redis集群问题
本来直接将redis为单独启动模式转为配置 yml文件 spring.redis.cluster.nodes: 192.168.12.78:8001,192.168.12.78:8002,192.168.12.78:8003, java文件 package io.sirc.config;import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.ann…...
JVMの内存泄漏内存溢出案例分析
1、内存溢出 内存溢出指的是程序在申请内存时,没有足够的内存可供分配,导致无法满足程序的内存需求,常见的内存溢出情况包括堆内存溢出(Heap Overflow)和栈溢出(Stack Overflow): …...
v31支架固定方式
CK_Label_v31 夹子固定方式 底座粘贴固定方式...
Jenkins从入门到精通面试题及参考答案(3万字长文)
目录 什么是Jenkins? Jenkins是如何工作的? Jenkins与持续集成(CI)有什么关系?...
如何使用电阻器?创建任何电阻的简单过程
您可能有一整盒E12 系列电阻器,但仍然无法获得足够接近您所需电阻的值。如果您需要 50 kΩ 电阻,接近的电阻是 47 kΩ。当然,这个误差在 10% 以内,但这对于您的应用程序来说可能还不够好。你会怎样做? 本文将介绍一个…...
学Python,看一篇就够
学Python,看一篇就够 python基础注释变量标识符命名规则使用变量认识bugDebug工具打断点 数据类型输出转义字符输入输入语法输入的特点 转换数据类型pycharm交互运算符的分类赋值运算符复合赋值运算符比较运算符逻辑运算符拓展 条件语句单分支语法多分支语法拓展 if…...
数据仓库核心:维度表设计的艺术与实践
文章目录 1. 引言1.1基本概念1.2 维度表定义 2. 设计方法2.1 选择或新建维度2.2 确定维度主维表2.3 确定相关维表2.14 确定维度属性 3. 维度的层次结构3.1 举个例子3.2 什么是数据钻取?3.3 常见的维度层次结构 4. 高级维度策略4.1 维度整合维度整合:构建…...
SQL实验 连接查询和嵌套查询
一、实验目的 1.掌握Management Studio的使用。 2.掌握SQL中连接查询和嵌套查询的使用。 二、实验内容及要求(请同学们尝试每道题使用连接和嵌套两种方式来进行查询,如果可以的话) 1.找出所有任教“数据…...
【JAVA WEB实用技巧与优化方案】Maven自动化构建与Maven 打包技巧
文章目录 一、MavenMaven生命周期介绍maven生命周期命令解析二、如何编写maven打包脚本maven 配置详解setting.xml主要配置元素setting.xml 详细配置使用maven 打包springboot项目maven 引入使用package命令来打包idea打包三、使用shell脚本自动发布四、使用maven不同环境配置加…...
详细分析Mysql中的SQL_MODE基本知识(附Demo讲解)
目录 前言1. 基本知识2. Demo讲解2.1 ONLY_FULL_GROUP_BY2.2 STRICT_TRANS_TABLES2.3 NO_ZERO_IN_DATE2.4 NO_ENGINE_SUBSTITUTION2.5 ANSI_QUOTES 前言 了解Mysql内部的机制有助于辅助开发以及形成整体的架构思维 对于基本的命令行以及优化推荐阅读: 数据库中增…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门  {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
安卓基础(aar)
重新设置java21的环境,临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的: MyApp/ ├── app/ …...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
算法:模拟
1.替换所有的问号 1576. 替换所有的问号 - 力扣(LeetCode) 遍历字符串:通过外层循环逐一检查每个字符。遇到 ? 时处理: 内层循环遍历小写字母(a 到 z)。对每个字母检查是否满足: 与…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
