Delphi2010中DataSnap技术网摘

一、为DataSnap系统服务程序添加描述

这几天一直在研究Delphi 2010的DataSnap,感觉功能真是很强大,现在足有理由证明Delphi7该下岗了。

DataSnap有三种服务模式,其中Service Application方式建立的Windows服务没有描述,描述部分是空的,可用如下方法添加服务描述:

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真是进步不少!

三、DataSnap服务器如何得到客户端的IP和端口

作为一个服务器软件,必须做到对客户端强有力的控制,想要控制,就必须得到客户端的网络基本信息,比如客户端IP和端口。有了客户端IP就能随心所欲操控客户端,比如终止某些客户端的连接、限制功能等等。

在Delphi2010中的DataSnap服务器如何获得客户端ip,的确花了我点时间,奇怪为什么这个功能不做的更人性化点呢,功能总是藏着掖着。还得让程序员像寻宝一样摸索,浪费时间。现在把我整理的结果奉献给大家,免得大家在花时间研究这个。

另外,通过研究发现,DSConnectEventObject.ChannelInfo.Id属性实际上是内存地址,并不是一个简单的数字。

以下代码中if .. then 里面的内容是关键。

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)
,);
end;

四、DataSnap中的TCP keepAlive和KeepAliveInterval(心跳包)参数详解

Delphi2010中DataSnap,如果客户端异常掉线或拔掉网线,那么在服务端会留下一个TCP连接,这个连接会变成死连接(经过测试,如果windows的TCP保持连接禁用的话,三个小时该死连接还不消失)。如果大量客户端并发,出现的死TCP连接过多,服务器内存和端口将会增加,直到占满服务器的端口和耗尽内存为止。如果这样的话,服务器无法健壮稳定的运行。

大家可以另开线程来监控客户端连接,但是今天要给大家讲解的不是这个方法,而是使用TCP协议自带的心跳包功能解决这个问题。

大家先了解一下 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 := ;
Val.KeepAliveTime := ;
Val.KeepAliveInterval := ;
WSAIoctl(ClientConnection.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or ,
@Val, SizeOf(Val), nil, , @Ret, nil, nil);
end;

观察上述代码,我们把心跳包放到服务端上执行,如果服务器的某个TCP连接在5秒钟没有收到数据,将会发送向对端发送心跳包,间隔3秒钟,连续发送5次(参数详解见上一讲高级技术4)。如果5次以后对端还没有应答,服务器将结束该TCP连接。TCP的连接可以使用 netstat -p tcp 命令查看。

当该TCP结束后,delphi编写的服务程序会自动结束和数据库的连接。我用的是FireBird数据库,大家可以使用命令查看

SELECT MON$USER, MON$REMOTE_ADDRESS,
MON$REMOTE_PID,
MON$TIMESTAMP
FROM MON$ATTACHMENTS

现在服务器的tcp死连接和数据库的死连接都清除了,我们的系统将能长期稳定的运行。

六、加强服务程序对访问者的控制能力 

1)作为一个服务程序,如果不限制客户端访问数量,后果将是很可怕的。如果有人恶搞,服务器不堪重负,内存将耗尽,最终服务器将宕机。如何限制访问者的数量呢?

我们可以设置一个变量,来记录来访者的数量,如果超过我们既定的数字,那么后续的连接服务器请求,都将被断掉。

2)限制了访问数量,但是如果不做密码身份认证,无关的人员也将能登陆服务器!解决办法是客户端传入用户名和密码,如果用户名和密码不正确,连接将被挂断。

在客户端的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 >= ) 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[, ]) <> '' then
ShowConnections.RowCount := ShowConnections.RowCount + ; ShowConnections.Cells[, ShowConnections.RowCount - ] := IntToStr
(DSConnectEventObject.ChannelInfo.Id);
ShowConnections.Cells[, ShowConnections.RowCount - ] :=
ClientConnection.Socket.Binding.PeerIP + ':' + IntToStr
(ClientConnection.Socket.Binding.PeerPort);
ShowConnections.Cells[, ShowConnections.RowCount - ] :=
DSConnectEventObject.ConnectProperties[TDBXPropertyNames.UserName];
ShowConnections.Cells[, ShowConnections.RowCount - ] :=
DSConnectEventObject.ConnectProperties[TDBXPropertyNames.Password];
ShowConnections.Cells[, ShowConnections.RowCount - ] := FormatDateTime
('yyyy-mm-dd hh:nn:ss', Now);
// ShowConnections.Cells[6, ShowConnections.RowCount - 1] :=
// DSConnectEventObject.ConnectProperties
// [TDBXPropertyNames.ServerConnection]; // 设置心跳包
val.OnOff := ;
val.KeepAliveTime := ;
val.KeepAliveInterval := ;
WSAIoctl(ClientConnection.Socket.Binding.Handle, IOC_IN or IOC_VENDOR or ,
@val, SizeOf(val), nil, , @Ret, nil, nil);
end;
end;

当然,之后的版本已无需手动加入心跳包代码了,因为TDSTCPServerTransport本身已经增加了相应的属性和功能,如:

Delphi 中DataSnap技术网摘的更多相关文章

  1. Delphi2010中DataSnap技术网摘

    一.为DataSnap系统服务程序添加描述 这几天一直在研究Delphi 2010的DataSnap,感觉功能真是很强大,现在足有理由证明Delphi7该下岗了. DataSnap有三种服务模式,其中 ...

  2. Delphi2010中DataSnap技术

    文章来源: https://blog.csdn.net/xieyunc/article/details/47865227?_t_t_t=0.3049736963513836 一.为DataSnap系统 ...

  3. Delphi中停靠技术的实现

    随着软件技术的不断进步,软件界面也越来越美观,操作也越来越方便.综观市面上比较专业的各种软件,我们会发现大部分都提供窗体停靠的功能,特别象工具软件,基本上都或多或少有停靠功能.自然,Delphi也支持 ...

  4. Delphi 中的DLL 封装和调用对象技术(刘艺,有截图)

    Delphi 中的DLL 封装和调用对象技术本文刊登2003 年10 月份出版的Dr.Dobb's 软件研发第3 期刘 艺摘 要DLL 是一种应用最为广泛的动态链接技术但是由于在DLL 中封装和调用对 ...

  5. Delphi 使用 Datasnap 的几种三层应用技术总结

    Delphi 使用 Datasnap 进行三层应用开发,积累了几种技术,总结如下: 1.(推荐!)在 Datasnap 服务端 使用 TDatasetProvider,客户端 使用   TDSProv ...

  6. Delphi2010中DataSnap高级技术(转)

    一. 为DataSnap系统服务程序添加描述 这几天一直在研究Delphi 2010的DataSnap,感觉功能真是很强大,现在足有理由证明Delphi7该下岗了. DataSnap有三种服务模式,其 ...

  7. Delphi中带缓存的数据更新技术

    一. 概念 在网络环境下,数据库应用程序是c/s或者是多层结构的模式.在这种环境下,数据库应用程序的开发应当尽可能考虑减少网络数据传输量,并且尽量提高并发度.基于这个目的,带缓存的数据更新技术应运而生 ...

  8. DELPHI中四种EXCEL访问技术实现

    一.引言 EXCEL在处理中文报表时功能非常强大,EXCEL报表访问也是信息系统开发中的一个重要内容,本文总结以往开发中所用到的几中EXCEL文件访问方法,在实际工作中也得到了很好的验证,本文列举了其 ...

  9. 让Delphi的DataSnap发挥最大效率

    让Delphi的DataSnap发挥最大效率 让Delphi的DataSnap发挥最大效率 一个DataSnap的应用程序由两个层组成: DataSnap服务器,它有一个带有一个或者更多DataSet ...

随机推荐

  1. MultipleActiveResultSets=true 数据库连接复用

    注:EF连接Mysql时,连接字符串是不能包含MARS的,Mysql不支持这个特性. ADO.NET 1.n 利用SqlDataReader读取数据,针对每个结果集需要一个独立的连接. 这些独立的链接 ...

  2. (原)linux下利用cmake来编译jthread开源库

    其实上次在用hisi3531平台的时候,就已经编译过一次这个库了,这次换了平台环境,交叉编译器变成了arm-hisiv100-linux-工具链,所以,没办法只能重新来过. 因为之前编译过,所以这次还 ...

  3. Websphere设置JVM时区解决程序、日志时间快8小时问题

    原文链接:http://www.itpub.net/thread-1204714-1-1.html 相信很多使用Websphere的朋友会经常在Windows操作系统中遇到程序时间快8小时的问题 如果 ...

  4. ASP.net MVC 文件下载的几种方法

      ASP.net MVC 文件下载的几种方法(欢迎讨论) 在ASP.net MVC 中有几种下载文件的方法前提:要下载的文件必须是在服务器目录中的,至于不在web项目server目录中的文件下载我不 ...

  5. 惊艳的HTML5动画特效及源码

    今天我们要来分享一些很酷的HTML5动画演示,HTML5的强大之处在于它可以利用canvas的特性来绘制很多普通网页无法完成的图形和动画,canvas就像一块超级画板,在上面不仅可以实现平面图形,而且 ...

  6. Yii2 响应部分 response

    当应用完成处理一个请求后, 会生成一个yii\web\Response响应对象并发送给终端用户 响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, 网页应用开发的最终目的本质上就是根据不同的 ...

  7. 【WP8】关于类库本地化问题

    WPToolkit中的ToggleSwitch开关控件是比较常用的控件,之前在做的的时候遇到一个问题,默认语言改为中文,手机系统语言也为中文,但是开关状态无法应用本地化的语言库,开关状态总是显示On/ ...

  8. Oracle统计每条数据的大小

    怎么查询一条记录到底占了多少空间呢,随便用一个表举例(如上图),就着解决眼前问题的原则(oracle),网上简单查了查,发现生效了,就没深入了解了,包括其它数据库怎么解决,都没做研究.Oracle下, ...

  9. 【python】泰语分词器安装

    1.安装icu http://blog.csdn.net/liyuwenjing/article/details/6105388 2.安装pyicu https://anaconda.org/kale ...

  10. SSM框架面试题及答案整理

    一.Spring面试题 1.Spring 在ssm中起什么作用? Spring:轻量级框架 作用:Bean工厂,用来管理Bean的生命周期和框架集成. 两大核心:①. IOC/DI(控制反转/依赖注入 ...