我创建了一个在Windows上运行的基于 TIdHTTPServer 的Web服务器。 Indy版本是最近的(2015年1月)。我将 MaxConnections 设置为1000,并且在调用 DoMaxConnections 时开发了一种重新启动Web服务器的机制。
每小时一次我记录连接数:
TIdThreadSafeList(IdHTTPServer1.Contexts).count;
在大多数情况下,连接数总是在增加。偶尔我会看到它减少(例如从525到520)。但整体趋势正在增加。大约5天后,它达到1000并且服务器重置(我知道1000相对较小,但不认为它与主题密切相关)。
即使在周末,当流量较低时,它仍会增加。我原本以为它会在流量较低时减少。为什么有些连接没有关闭?
我 netstat -an 并看到很多 TIME_WAIT 状态。
其他相关的源代码:
ServerIOHandler := TIdServerIOHandlerSSLOpenSSL.Create(self);
ServerIOHandler.SSLOptions.CertFile := 'C:\xxxxxx.crt';
ServerIOHandler.SSLOptions.KeyFile := 'C:\xxxxxx.key';
ServerIOHandler.SSLOptions.RootCertFile := 'C:=xxxxxx.crt';
ServerIOHandler.SSLOptions.Method := sslvSSLv23;
ServerIOHandler.SSLOptions.Mode := sslmServer;
IdHTTPServer1 := TIdHTTPServer.Create;
IdHTTPServer1.MaxConnections := 1000;
IdHTTPServer1.AutoStartSession := True;
IdHTTPServer1.KeepAlive := True;
IdHTTPServer1.SessionState := True;
IdHTTPServer1.OnCommandGet := MainGet;
idHttpServer1.ParseParams := True;
idHttpServer1.IOHandler := ServerIOHandler;
idHttpServer1.Bindings.Add.Port := 80;
idHttpServer1.Bindings.Add.Port := 443;
IdHTTPServer1.Active := True;
更新我认为添加一些netstat统计信息会很有用。
服务器运行24小时以上:
Contexts Count: 587
netstat ESTABLISHED from external to port 80:580
netstat TIME_WAIT from external to port 80:819
然后我重新启动了我的Indy服务(但是没有重启Windows服务器):
Contexts Count: 60
netstat ESTABLISHED from external to port 80:49
netstat TIME_WAIT from external to port 80:797
更新2 - 要求显示 MainGet 程序。可行的代码太多了。但我所做的是提供可以解决问题的代码片段。下面列出了我正在进行的一些通话(在不同情况下提高性能)。
AResponseInfo.ContentText := filetostring('c:\.....');
AResponseInfo.ResponseNo
Aresponseinfo.RawHeaders.Add('Connection:close');
Aresponseinfo.CustomHeaders.Add('Keep-Alive: timeout=30');
Aresponseinfo.Connection:='keep-alive';
AResponseInfo.ContentStream := MemoryStream;
AResponseInfo.Redirect('xxxxx');
AResponseInfo.ServeFile(AContext,mFile);
AResponseinfo.CacheControl:='max-age=1209600';
更新3 - 提供有关 MainGet 功能的其他信息。我正在跟踪函数被调用的次数和它退出的次数。 iGlobalGetStart和iGlobalGetFinish的值总是非常接近(当然比活跃的上下文数量少)。
procedure TMyWebUnit.MainGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
try
InterlockedIncrement(iGlobalGetStart);
.... all of my logic
finally
InterlockedIncrement(iGlobalGetFinish);
end;
更新4 - 我已实施其他跟踪代码。我创建了自己的类,来自 TIdServerContext 。在其中我设置了它的创建日期/时间,并且还有一个名为DatetimeLastUsed的日期/时间成员,它将在 oncommandget 中更新。这是班级:
type
TEAIdServerContext = class(TIdServerContext)
DateTimelastUsed,DateTimeCreated: TDateTime;
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
destructor Destroy; override;
end;
我将 IdHTTPServer1.ContextClass 设置为这个新类: IdHTTPServer1.ContextClass:= TEAIdServerContext;
在我的 OnCommandGet 中,我要做的第一件事就是将 DateTimeLastUsed 的日期/时间设置为当前时间:
TEAIDServerContext(AContext).DateTimeLastUsed := Now;
我还有一个列出所有上下文的函数:
procedure SayContexts();
var
i: Integer;
mstring: String;
mList: TList;
begin
mList := IdHTTPServer1.Contexts.LockList;
mstring := 'Contexts:'+inttostr(mlist.Count);
with mList do try
for i := 0 to count -1 do begin
mString := mString +
datetimetostr(TEAIDServerContext(mList[i]).datetimecreated)+'; last used:'+datetimetostr(TEAIDServerContext(mList[i]).datetimeLastUsed)
end;
end;
IdHTTPServer1.Contexts.UnLockList;
....
end;
保持打开的连接永远不会进入 oncommandget 代码,因为它们的datetimelastused字段为null。这是正常的吗?