将一个局域网的AD0的mis程序升级到互联网的方法(散分 前 6 人 50分 ,感兴趣 的 问我要测试程序) ( 积分: 300 )

  • 主题发起人 主题发起人 hfghfghfg
  • 开始时间 开始时间
H

hfghfghfg

Unregistered / Unconfirmed
GUEST, unregistred user!
将一个局域网的AD0的mis程序升级到互联网的方法:
1。直接用tcpip:1433连接。“ 路由后的内网”,“代理” 好像有些问题?
ok,俺用VNN,或者VPN。虽然有点不顾江湖道义。但也是一种方法。
这一招的名称叫做:“它山之石”
2。TWebConnection/TSocketConnection。改起来也快。偷懒的人可以
如下处理:DataSetProvider使用[poAllowCommandText],然后写一
个工具,替换修改*.pas,*.dfm的代码(控件名字无需改,只改定义
,然后就是
SQL.Clear > CommandText:=''
SQL.Text:='???????' > CommandText:= '???????'
SQL.Add('????') > CommandText:=CommandText+'????'#13#10
)。几百窗体的普通程序也用不了一两天。

这一招的名称叫做:“见山不是山,见水不是水”,看上去是个
ADOQuery(名字:“ADOQry_select”),其实是个ClientDataSet。(这是
同事说的)

ps:改之前要备份好。改完了顺道改了delphi自带的
httpsrvr 或者scktsrvr (个人建议)。
3。使用ADO2.5以后的新特性(流支持 见附录),改了ADODB.pas。
例如
在TADOConnection加
public
Httphost: string;
HttpConnected: boolean;
我用了HTTP,其实也可用udp,tcpip等等,你要不嫌慢用串口也行。
另外写了几个函数(见附录)。我把改了的ADODB.pas复制的我的程序
目录里,加了一句
ADOConnection1.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
编译一下,运行,俺的程序就 晃晃悠悠的运行在web服务器的数据库下
了。另外我做了与TWebConnection/TSocketConnection的性能比较测试。

每次查询top 1 条记录(每个表查一次,循环10次)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 0.723 1.781


每次查询top 60 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 1.917 2.792



每次查询top 400 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 5.113 3.846


SocketConnection在查询记录多时,有时停很久。

我在数据传输时用了zlib压缩。

另外delphi 通过
Import Type Library 导入
C:/Program Files/Common Files/System/ado.msado26.tlb
生成的声明最好不要用。

俺之所以这样用的 原因:
1。以前的程序可以轻松的使用互联网的数据库
只需根据设置决定是否执行
ADOConn.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
2。WebConnection速度慢,SocketConnection大数据量下也不好。
3。这样改的程序可以可以通过设置在局域网中依然用原来的
模式(速度快)。例如
if DebugHook=0 then
ADOConn.Httphost := 'http://220.203.0.??/logserver/sql.dll/sql'
else
....................
这样可以在delphi 调试时连本地库(速度快 呵呵)。
一句话,就是灵活了。


缺点:
事务 与WebConnection 一样,自己处理。

其实 这种方法是邪派的,不过我经常遇到一些问题,时间紧,就只好用邪派的招数了。
以前要一天内将一个access的程序(我记得好像是121个窗体)改到sql server上,同时
access的版本也要一直继续下去,因为客户的环境不一样。当时我也是改了ADODB.pas,
主要是加了一个sql转换的环节,即将access的某些函数转为sql server 的,如:
trim() > ltrim(rtrim()) instr > charindex 等 另外配合一些sql server 自定义
的函数 。
正统的做法,改成b/s的吧。因为如果使用web的数据,整体的设计思路不一样,例如,如
果要用WebConnection 你要注意连接的次数,事物处理,脱机时的处理。注意这是正统,
不是正确,正确的方法要视情况定,时间,人手,性能要求,后续发展。。。。。。。。。。。

http://220.203.0.??/svr/sql.dll
是自己随手写的(delphi),你用asp写也可以(附录ADO的例子)。

这一招的名称叫做:“暗渡陈仓”


qq: 105204912 鸽子(花间一壶酒,手上两猪蹄。程序员嘛,自然要多啃猪蹄啦。俗话
说的好,以形补形,俺可是耍手指头的,多啃几只 加 功力 啊。有蹄又岂能无酒,
所谓 酒入肥肠,化作字千行。)

元旦过后 我就改用 Dot Net 了。以后灌水就少了。
下一个灌水的 题目 是 本地数据库 与 网络数据库 的 同步。

前一段时间 我用C#写了一个socket 的信息服务,感觉C#的
线程很特别,有朋友也是用C#的多多交流。



附录
ADO 程序员参考
流和持久性
Recordset 对象的 Save 方法将 Recordset 保存或者持久保留到文件中,
而 Open 方法则从该文件中恢复 Recordset。
现在,Save 和 Open 方法也可以将 Recordset 持久保留到 Stream 对象中。
此功能尤其有助于使用远程数据服务 (RDS) 和 Active Server Pages (ASP)。
方案 4:

在本方案中,ASP 代码将 Recordset 的内容以 ADTG 格式写入客户端。Cursor Service 可以用此数据创建断开连接的 Recordset。

RDS DataControl 的新属性 URL 指向生成 Recordset 的 .asp 页。这意味着获取 Recordset 对象不需要 RDS 使用服务器端 DataFactory 对象,也不需要用户编写业务对象。因此大大简化了 RDS 编程模型。

名为 http://server/directory/recordset.asp 的服务器端代码如下:

<%
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "select au_fname, au_lname, phone from Authors", "dsn=Pubs"
response.ContentType = "multipart/mixed"
rs.Save response, adPersistADTG
%>

客户端代码:

<HTML>
<HEAD>
<TITLE>RDS Query Page</TITLE>
</HEAD>
<body>
<CENTER>
<H1>Remote Data Service 2.5</H1>
<TABLE DATASRC="#DC1">
<TR>
<TD><SPAN DATAFLD="au_fname"></SPAN></TD>
<TD><SPAN DATAFLD="au_lname"></SPAN></TD>
<TD><SPAN DATAFLD="phone"></SPAN></TD>
</TR>
</TABLE>
<BR>

<OBJECT classid="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID=DC1 HEIGHT=1 WIDTH = 1>
<PARAM NAME="URL" VALUE="http://server/directory/recordset.asp">
</OBJECT>

</SCRIPT>
</BODY>
</HTML>

开发人员还可以选择在客户端使用 Recordset 对象。

...
function GetRs()
{
rs = CreateObject("ADODB.Recordset");
rs.Open "http://server/directory/recordset.asp"
DC1.SourceRecordset = rs;
}
...



增加的函数
procedure makeUpstream(s: TMemoryStream; action, sql, memo1, memo2: string);
procedure getRS_stream(ms_Down: TMemoryStream; var errmsg: string; ms_rs: TMemoryStream);

function HttpPutStram(url: string; s_up, s_down: TMemoryStream): Boolean;

function RecordsetFromMS(Stream: TMemoryStream): _Recordset;

function RecordsetFromHttp(Host, sql: string): _Recordset;
function ExecFromHttp(Host, sql: string; NoRecords: boolean; var c: integer): _Recordset;
function HttpConnect(host: string): boolean;
function Http_GetFieldNames(host, tb: string; ss: TStrings): boolean;
function Http_GetTableNames(host: string; sys: boolean; ss: TStrings): boolean;


function GetSql(Text: string; p: TParameters): string;

修改
procedure TADOConnection.DoConnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := HttpConnect(Httphost);

procedure TADOConnection.DoDisconnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := false;
end

procedure TADOConnection.Execute(const CommandText: WideString;
var RecordsAffected: Integer; const ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
var
VarRecsAffected: OleVariant;
begin
if trim(Httphost) <> '' then
begin
ExecFromHttp(trim(Httphost), CommandText, true, RecordsAffected);

function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
var
VarRecsAffected: OleVariant;
i: integer;
begin
if trim(Httphost) <> '' then
begin
Result := ExecFromHttp(trim(Httphost), CommandText, false, i);

procedure TADOConnection.Open(const UserID, Password: WideString);
begin
if trim(Httphost) <> '' then
begin


procedure TADOConnection.GetFieldNames(const TableName: string;
List: TStrings);
const
COLUMN_NAME = 'COLUMN_NAME'; { Do not localize }
var
Fields: _Recordset;
begin
if trim(Httphost) <> '' then
begin
Http_GetFieldNames(Httphost, TableName, list);

procedure TADOConnection.GetTableNames(List: TStrings;
SystemTables: Boolean);
var
TypeField,
NameField: TField;
TableType: string;
DataSet: TADODataSet;
begin
if trim(Httphost) <> '' then
begin
Http_GetTableNames(Httphost, SystemTables, List);

function TADOConnection.GetConnected: Boolean;
begin
if trim(Httphost) <> '' then
begin
Result := HttpConnected;


function TParameters.InternalRefresh: Boolean;
procedure TADOCommand.OpenConnection;
function TADOCommand.Execute(var RecordsAffected: Integer;
const Parameters: OleVariant): _Recordset;
procedure TCustomADODataSet.OpenCursor(InfoQuery: Boolean);
 
将一个局域网的AD0的mis程序升级到互联网的方法:
1。直接用tcpip:1433连接。“ 路由后的内网”,“代理” 好像有些问题?
ok,俺用VNN,或者VPN。虽然有点不顾江湖道义。但也是一种方法。
这一招的名称叫做:“它山之石”
2。TWebConnection/TSocketConnection。改起来也快。偷懒的人可以
如下处理:DataSetProvider使用[poAllowCommandText],然后写一
个工具,替换修改*.pas,*.dfm的代码(控件名字无需改,只改定义
,然后就是
SQL.Clear > CommandText:=''
SQL.Text:='???????' > CommandText:= '???????'
SQL.Add('????') > CommandText:=CommandText+'????'#13#10
)。几百窗体的普通程序也用不了一两天。

这一招的名称叫做:“见山不是山,见水不是水”,看上去是个
ADOQuery(名字:“ADOQry_select”),其实是个ClientDataSet。(这是
同事说的)

ps:改之前要备份好。改完了顺道改了delphi自带的
httpsrvr 或者scktsrvr (个人建议)。
3。使用ADO2.5以后的新特性(流支持 见附录),改了ADODB.pas。
例如
在TADOConnection加
public
Httphost: string;
HttpConnected: boolean;
我用了HTTP,其实也可用udp,tcpip等等,你要不嫌慢用串口也行。
另外写了几个函数(见附录)。我把改了的ADODB.pas复制的我的程序
目录里,加了一句
ADOConnection1.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
编译一下,运行,俺的程序就 晃晃悠悠的运行在web服务器的数据库下
了。另外我做了与TWebConnection/TSocketConnection的性能比较测试。

每次查询top 1 条记录(每个表查一次,循环10次)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 0.723 1.781


每次查询top 60 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 1.917 2.792



每次查询top 400 条记录
(每个表查一次,循环10次 有的表没有记录 或只有几条记录,80%的表还
是有不少记录的)
耗时比:
ado by hfghfghfg SocketConnection WebConnection
1 5.113 3.846


SocketConnection在查询记录多时,有时停很久。

我在数据传输时用了zlib压缩。

另外delphi 通过
Import Type Library 导入
C:/Program Files/Common Files/System/ado.msado26.tlb
生成的声明最好不要用。

俺之所以这样用的 原因:
1。以前的程序可以轻松的使用互联网的数据库
只需根据设置决定是否执行
ADOConn.Httphost := 'http://220.203.0.??/svr/sql.dll/sql';
2。WebConnection速度慢,SocketConnection大数据量下也不好。
3。这样改的程序可以可以通过设置在局域网中依然用原来的
模式(速度快)。例如
if DebugHook=0 then
ADOConn.Httphost := 'http://220.203.0.??/logserver/sql.dll/sql'
else
....................
这样可以在delphi 调试时连本地库(速度快 呵呵)。
一句话,就是灵活了。


缺点:
事务 与WebConnection 一样,自己处理。

其实 这种方法是邪派的,不过我经常遇到一些问题,时间紧,就只好用邪派的招数了。
以前要一天内将一个access的程序(我记得好像是121个窗体)改到sql server上,同时
access的版本也要一直继续下去,因为客户的环境不一样。当时我也是改了ADODB.pas,
主要是加了一个sql转换的环节,即将access的某些函数转为sql server 的,如:
trim() > ltrim(rtrim()) instr > charindex 等 另外配合一些sql server 自定义
的函数 。
正统的做法,改成b/s的吧。因为如果使用web的数据,整体的设计思路不一样,例如,如
果要用WebConnection 你要注意连接的次数,事物处理,脱机时的处理。注意这是正统,
不是正确,正确的方法要视情况定,时间,人手,性能要求,后续发展。。。。。。。。。。。

http://220.203.0.??/svr/sql.dll
是自己随手写的(delphi),你用asp写也可以(附录ADO的例子)。

这一招的名称叫做:“暗渡陈仓”


qq: 105204912 鸽子(花间一壶酒,手上两猪蹄。程序员嘛,自然要多啃猪蹄啦。俗话
说的好,以形补形,俺可是耍手指头的,多啃几只 加 功力 啊。有蹄又岂能无酒,
所谓 酒入肥肠,化作字千行。)

元旦过后 我就改用 Dot Net 了。以后灌水就少了。
下一个灌水的 题目 是 本地数据库 与 网络数据库 的 同步。

前一段时间 我用C#写了一个socket 的信息服务,感觉C#的
线程很特别,有朋友也是用C#的多多交流。



附录
ADO 程序员参考
流和持久性
Recordset 对象的 Save 方法将 Recordset 保存或者持久保留到文件中,
而 Open 方法则从该文件中恢复 Recordset。
现在,Save 和 Open 方法也可以将 Recordset 持久保留到 Stream 对象中。
此功能尤其有助于使用远程数据服务 (RDS) 和 Active Server Pages (ASP)。
方案 4:

在本方案中,ASP 代码将 Recordset 的内容以 ADTG 格式写入客户端。Cursor Service 可以用此数据创建断开连接的 Recordset。

RDS DataControl 的新属性 URL 指向生成 Recordset 的 .asp 页。这意味着获取 Recordset 对象不需要 RDS 使用服务器端 DataFactory 对象,也不需要用户编写业务对象。因此大大简化了 RDS 编程模型。

名为 http://server/directory/recordset.asp 的服务器端代码如下:

<%
Dim rs
Set rs = Server.CreateObject("ADODB.Recordset")
rs.Open "select au_fname, au_lname, phone from Authors", "dsn=Pubs"
response.ContentType = "multipart/mixed"
rs.Save response, adPersistADTG
%>

客户端代码:

<HTML>
<HEAD>
<TITLE>RDS Query Page</TITLE>
</HEAD>
<body>
<CENTER>
<H1>Remote Data Service 2.5</H1>
<TABLE DATASRC="#DC1">
<TR>
<TD><SPAN DATAFLD="au_fname"></SPAN></TD>
<TD><SPAN DATAFLD="au_lname"></SPAN></TD>
<TD><SPAN DATAFLD="phone"></SPAN></TD>
</TR>
</TABLE>
<BR>

<OBJECT classid="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"
ID=DC1 HEIGHT=1 WIDTH = 1>
<PARAM NAME="URL" VALUE="http://server/directory/recordset.asp">
</OBJECT>

</SCRIPT>
</BODY>
</HTML>

开发人员还可以选择在客户端使用 Recordset 对象。

...
function GetRs()
{
rs = CreateObject("ADODB.Recordset");
rs.Open "http://server/directory/recordset.asp"
DC1.SourceRecordset = rs;
}
...



增加的函数
procedure makeUpstream(s: TMemoryStream; action, sql, memo1, memo2: string);
procedure getRS_stream(ms_Down: TMemoryStream; var errmsg: string; ms_rs: TMemoryStream);

function HttpPutStram(url: string; s_up, s_down: TMemoryStream): Boolean;

function RecordsetFromMS(Stream: TMemoryStream): _Recordset;

function RecordsetFromHttp(Host, sql: string): _Recordset;
function ExecFromHttp(Host, sql: string; NoRecords: boolean; var c: integer): _Recordset;
function HttpConnect(host: string): boolean;
function Http_GetFieldNames(host, tb: string; ss: TStrings): boolean;
function Http_GetTableNames(host: string; sys: boolean; ss: TStrings): boolean;


function GetSql(Text: string; p: TParameters): string;

修改
procedure TADOConnection.DoConnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := HttpConnect(Httphost);

procedure TADOConnection.DoDisconnect;
begin
if trim(Httphost) <> '' then
begin
HttpConnected := false;
end

procedure TADOConnection.Execute(const CommandText: WideString;
var RecordsAffected: Integer; const ExecuteOptions: TExecuteOptions = [eoExecuteNoRecords]);
var
VarRecsAffected: OleVariant;
begin
if trim(Httphost) <> '' then
begin
ExecFromHttp(trim(Httphost), CommandText, true, RecordsAffected);

function TADOConnection.Execute(const CommandText: WideString;
const CommandType: TCommandType = cmdText;
const ExecuteOptions: TExecuteOptions = []): _Recordset;
var
VarRecsAffected: OleVariant;
i: integer;
begin
if trim(Httphost) <> '' then
begin
Result := ExecFromHttp(trim(Httphost), CommandText, false, i);

procedure TADOConnection.Open(const UserID, Password: WideString);
begin
if trim(Httphost) <> '' then
begin


procedure TADOConnection.GetFieldNames(const TableName: string;
List: TStrings);
const
COLUMN_NAME = 'COLUMN_NAME'; { Do not localize }
var
Fields: _Recordset;
begin
if trim(Httphost) <> '' then
begin
Http_GetFieldNames(Httphost, TableName, list);

procedure TADOConnection.GetTableNames(List: TStrings;
SystemTables: Boolean);
var
TypeField,
NameField: TField;
TableType: string;
DataSet: TADODataSet;
begin
if trim(Httphost) <> '' then
begin
Http_GetTableNames(Httphost, SystemTables, List);

function TADOConnection.GetConnected: Boolean;
begin
if trim(Httphost) <> '' then
begin
Result := HttpConnected;


function TParameters.InternalRefresh: Boolean;
procedure TADOCommand.OpenConnection;
function TADOCommand.Execute(var RecordsAffected: Integer;
const Parameters: OleVariant): _Recordset;
procedure TCustomADODataSet.OpenCursor(InfoQuery: Boolean);
 
呵呵~~~非常好,狂顶顶顶顶!!!!
 
能学习,还有分拿,呵呵,鸽子真好啊
 
谢谢!顶一下
 
顶顶,我也想做成这个样子的
 
先拿分
一会儿再细看
 
老大,你是雷锋吗?
 
我也来拿分了
 
不好,来晚了,但是我还是想要分! [:D]
 
我想要测试程序.
wgm_hefei@126.com
 
to wyf_hefei
qq:105204912
 
SocketConnection在查询记录多时,有时停很久。

是不是因为用了压缩的缘故, 能否进行优化呢?
 
很好。
不过,有人研究出这方面的控件了。
 
to lich
因为 scktsrvr 有一个 bug (超线程时)
 
to XLR2003
我这样 做的 原因 其实 是最快的升级自己程序

同时 要 减少维护
至少 sql server ,access ,web,局域网 是一个 版本。
而且 可以自由 切换。
还不必换控件。
 
那么这个Bug能否进行修正?
 
后退
顶部