SOS CGI编程问题(100分)

  • 主题发起人 主题发起人 yxuehui
  • 开始时间 开始时间
Y

yxuehui

Unregistered / Unconfirmed
GUEST, unregistred user!
小弟在编CGI时,CGI已经编译通过,发现以下问题:
当一个人不停的重复某一CGI请求时(每秒至少3次),由于是局域网,
速度很快,所以,那么多请求一下子就过去了,而Web Server端因此
而处于拥塞状态,导致所有的CGI请求和普通网页的请求都无法得到
返回.这时候,CPU基本空闲,执行其它应用程序不成问题.
请问各位大虾,如何解决该问题.
本人用的Web Server是IIS
 
据我的理解,CGI是在网页上调用的,譬如计数器之类的,若按你的说法则是
使用方法的问题。
 
没道理的,你的CGI做什么的?详细点
 
改为isapi看看行不行,isapi是用线程来处理请求的.
 
我的CGI是对一个Paradox数据库进行操作,然后返回结果.
我曾经尝试把它改为ISAPI,但是总是出错.
 
把我的CGI改成ISAPI后,执行请求后出现以下错误.

Internal Server Error 500
Exception: Exception
Message: No data modules registered

session的autoSessionName:=true,不知是否SESSION别的属性也要设置.
 
yxuehui, 这个问题在我自己的WEB数据访问时也碰到过

主要原因在 你做的CGI 中使用了单个的SESSION,而且是单机使用的PARADOX
多人操作WEB数据库时,有可能第一个请求没结束,第二个就到了

故障
首先,如果你用的是一个SESSION,那么第一个用户使用QUERY查询结果
第二个用户也发出查询请求,由于只有一个SESSION。所以这时候数据集的
指针就发生变化, 所以我建议你对每一个请求都生成一个SESSION,
然后每一个用户单独使用自己的SESSION访问
否则就会出你所说的错误

第二,
由于PARADOX是单机数据库,所以如果你的应用里需要插入或修改新数据
的时候,要妥善处理数据表的锁定问题。 建议你使用INTRABASE
或 SQL SERVER之类的做数据库SERVER,毕竟他们都是支持网络多人
并发操作的。而PARADOX不支持多线程更新。

第三,
即使你改成了 ISAPI方式访问数据库的话, 一定也要象 第一条说的那样
因为ISAPI使用公用DLL方式
 
谢谢王寒松的指点.
如何让每一个用户单独使用自己的SESSION访问?
是使用多个session控件还是在session属性中设置.
 
因为你的查询很可能是多人同时访问,所以会在SERVER里
产生多个实例运行同样的查询, 所以你的问题其实和这个问题是一样的
需要动态生成 SESSION
看这里
<a href="http://www.gislab.ecnu.edu.cn/delphibbs/DispQ.asp?LID=113978
">各位数据库的高手,请教一下关于数据库Session的DLL传递问题 </a>
 
to yxuehui: CGI程序没有王寒松所说的Session问题,但是有数据表锁定问题。
CGI服务程序是单线程的,每次用户调用的时候就创建一个程序例证,自然就创建一个新的
Session。同时调用的用户多了以后,服务器端的程序例证会大量增加,CPU的负担会十分
繁重,所以如果用户较多的时候应该使用ISAPI。

数据库同时只允许一个客户修改数据,当修改数据的时候自动LOCK数据库。当有人正在修
改数据的时候,其他人请求修改数据库就会产生错误。解决办法为,在接受到修改数据请求
后,用一个限时的While循环测数据库是否被锁定,直到不被锁定的时候才修改数据库并跳
出循环;如果超时,则返回主机忙的消息给客户。
 
yxuehui,我遇到的问题和你一样,而且经常发生,我的cgi 5-10次/秒。
解决的办法有两个:
1、使用一个线程在几秒中之内终止cgi
procedure TTerminateMe.execute;
begin
sleep(Time);
ExitProcess(0);
end;

constructor TTerminateMe.create(ATime:integer);
begin
inherited create(false);
Time :=ATime;
end;
在cgi开始时启动这个线程. Time取 5-10,退出时,作一些处理。

2、另一个方法改用isapi.
 
To huizhang:我做过试验,当只有3个用户同时请求,CGI对数据库只进行读
操作,系统就死了.我的机器开始PII266,64M内存,所以系统资源肯定没有问题.
后来我该同SQL server6.5的数据库,出同样的问题.
您说的方法我也用了,但是没有一个请求返回我定义的超时信息,我估计,程序在
执行到那里之前系统就已经死锁了.

To fuliang:
其实我用DELPHI时间不长,属于即学即用那种,您所提的方法可否再详细一点
论述.或发到我的信箱.

通过几天的试验,我觉得不是数据库不能并行读写的问题,会不会是BDE的问题?
 
如果你只是查询,那应该没问题。你可以在本机上调试,调用到某个位置就用
SHOWMESSAGE显示进程,也可以作一个LOG文件,把用户的请求都存到LOG文件中以便
检查。

再不行你把源程序贴过来,让大家帮你分析一下
 
应该是bde的问题。bde的问题好多。
如果你的访问量不大,你在程序结尾加一个 dbiexit函数。
好象在bde单元中。也许会好。
 
我的访问量大概是每秒10个访问者。
cgi返回的错误是:
Exception EDBEngineError in modeule bdeadmin.exe at 00054F92.
An error occurred while attempting to initialize the Borland Database
Engine (error $2A04).

在NT下,杀不了已经请求了的CGI程序。
下面付一段简单的测试程序。
使用的数据库为Sql6.5 数据库。
procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
var userIp:string;
accesstimes:integer;
html:string;
begin
UserIp:=request.RemoteAddr ;
html:='<html><head><title>测试CGI</title></head><body><p>';
if ss1.Active =false then
ss1.Active :=true;
if tb.active=false then tb.Active :=true;

if tb.Locate('Ip',userIp,[loCaseinsensitive]) then
begin
accesstimes:=tb.fieldbyname('access').asinteger;
accesstimes:=accesstimes+1;
tb.Edit;
tb.FieldByName('access').asinteger:=accesstimes;
tb.post;
html:=html+'<h1>您第'+inttostr(accesstimes)+'次从'+UserIp +'来访问这个站点,谢谢!';
end
else
begin
tb.AppendRecord([UserIp,1]);
html:=html+'<h1>您第1次从'+UserIp +'来访问这个站点,谢谢!';
end;
tb.Active :=false;
ss1.Active :=false;
html:=html+'</P><p><h1><a href="http://202.112.97.72/examweb/cgi-bin/testSQL.exe">请再次访问</a></body></html>';
response.content:=html;


end;

end.
 
如果你的cgi程序每秒十个访问者估计是撑不住的(程序测试和实际情况往往不一样),建议不要使用数据库。如果非要使用,建议加一个临界区 TEvent. 方法是:
var
Conflict:TEvent; // 避免冲突的事件--每次只让一个程序运行

initialization
// Conflict win32 事件避免cgi重入
Conflict :=TEvent.Create(nil,false,true,'Conflict');
Conflict.waitFor($ffffffff);
finalization
Conflict.SetEvent; // 设置程序退出
end.

并保证你的程序运行时间很短(<1ms), 上面给的程序是针对win-cgi的,对isapi要把 TEvent.create方到初始化段,其他放到请求过程中。

另外还建议在程序末尾加 dbiexit(isapi除外);
 
我用的是标准CGI ,用上述方法也行吗。
好象编译不过去。
 
俺的歪招:
你在你的WINCGI 响应请求的时候先做一个处理

建立一个 请求列表, 这个列表里记录着 请求者的IP地址,和他的请求CONTENT

在一个请求到来时,先在列表里寻找有没有相同的IP相同的CONTENT 存在
如果有的话, 就忽略掉这个请求(不做处理), 如果没有,就把他的要求放到
请求列表里

在数据库响应完毕访问者请求后, 从请求列表里删除掉对应的请求

以此实现过滤过度请求

由于此时已经没有多余的请求在列表里,所以如果在这种情况下如果你的服务器
还是无法满足用户访问的话,那就只好换个服务器平台或换更好的服务器
 
如果编译不过加上 syncobjs 单元 和 bde单元。
肯定能过,我就是这么做的!
 
这个问题的确棘手,我最后把部分程序该成了ISAPI,该问题似乎得到了
解决。回想起以前用各位大侠交的招数,效果都不是特别好,这边的矛盾解决了
那里又出问题。可能不是数据库的问题,因为Paradox可以在同一个库
里对不同的记录进行同时读写操作(我做过测试)。 …………
…… ……
至于database desktop的问题,我把BDE配置里的INI中的autoOBDC的
属性该为true,似乎database desktop就不会把目录LOCK.

在编写ISAPI过程中,也遇到了很多问题,还要向大家请教。
由于小弟的分数有限,这次讨论的分数我只好给大家分点了。大家帮我度过了
最艰难最烦恼的一星期。
谢谢!
 
后退
顶部