100分拜求高手:ClientSocket组件动态创建问题(急!)(100分)

  • 主题发起人 wuhanxupan
  • 开始时间
W

wuhanxupan

Unregistered / Unconfirmed
GUEST, unregistred user!
现在正参与一个关于tcpip的项目,软件负责在多个设备之间控制和协调通信,每个设备都内置miniOS操作系统,设备和软件之间用tcpip协议通信,软件需要长时间运行(几个月不关机),我使用的是ClientSocket组件与设备通信。由于现场网络环境恶劣,可能出现tcp假连接现象,我于是在与每个设备连接时加入了类似‘脉搏跳动’的机制来确保通信正常。又由于设备数量不确定(最多时可能会有100台),我于是采用运行时动态创建多个ClientSocket对象实例的方式与设备通信,起初软件都能正常运行,但几天后tcp通信部分工作不再正常,查看以后发现windows任务管理器中的进程的句柄数居然有8000多个,每当设备不响应‘脉搏’数据包(比如设备断电),软件重连接时句柄数就会增加。现在我怀疑是我在动态创建ClientSocket组件时没有处理好,因为我另外做了一个测试程序,在设计时添加了ClientSocket组件,重连接时不会有句柄的增加。
现将代码罗列如下:
动态生成ClientSocket部分:
nCount:=DevIni.ReadInteger('设备总数','数量',0);
if nCount>0 then
begin
SetLength(PingState,nCount);
SetLength(PingSockets,nCount);
for i:=0 to nCount-1 do
begin
PingState:=0;
PingSockets:=TClientSocket.Create(self);
PingSockets.Tag:=i;
PingSockets.Name:='SocketClient'+inttostr(i+1);
PingSockets.OnRead:=OnSocketsRead;
PingSockets.OnError:=OnSocketsError;
PingSockets.OnConnect:=OnSocketsConnect;
DevIP:=DevIni.ReadString('设备'+inttostr(i+1),'IP','0');
if DevIP<>'0' then
begin
PingSockets.Close;
PingSockets.Host:=DevIP;
PingSockets.Port:=10000;
PingSockets.Open;
end;
end;
Timer2.Enabled:=false;
Timer2.Interval:=7000;
Timer2.Enabled:=true;
end;
脉搏定时器:
procedure TForm1.Timer2Timer(Sender: TObject);
var
i,nLen:integer;
begin
Timer2.Enabled:=false;
nLen:=Length(PingSockets);
for i:=0 to nLen-1 do
begin
PingState:=0;
if Assigned(PingSockets) then
begin
if PingSockets.Active then
PingSockets.Socket.SendText('10');//设备会自动回复此命令
end;
AddLog('连接设备'+inttostr(i+1)+#13);
end;
Timer3.Enabled:=false;
Timer3.Interval:=500;
Timer3.Enabled:=true;
Timer2.Enabled:=true;
end;
重连接定时器:如果500ms后未收到数据就重新连接
procedure TForm1.Timer3Timer(Sender: TObject);
var
i,nLen:integer;
hExe:THandle;
begin
Timer3.Enabled:=false;
nLen:=Length(PingState);
for i:=0 to nLen-1 do
begin
if (PingState=0)then
begin
AddLog('设备'+inttostr(i+1)+'连接中断'+#13);
PingSockets.Close;
PingSockets.Host:=DevIni.ReadString('设备'+inttostr(i+1),'IP','0');
PingSockets.Port:=10000;
PingSockets.Open;//此处句柄增加
Inc(ReopenCount);
AddLog('重新连接计数:'+inttostr(ReopenCount)+#13);
end;
end;
end;
OnRead事件处理:
procedure TForm1.OnSocketsRead(Sender: TObject;
Socket: TCustomWinSocket);
var
i:integer;
szData:string;
begin
i:=(Sender as TClientSocket).Tag;
PingState:=1;
szData:=(Sender as TClientSocket).Socket.ReceiveText;
AddLog('从设备'+inttostr(i+1)+'收到数据'+szData+#13);
end;
 
并没有看到free ClientSocket的地方,估计是socket handle没被释放
 
两点建议:
1 如果通信稳定性要求高尽量用api而不要用控件
2 每次通信应有回执,如果收不到回执就认为连接失效,重连重发
3 如有可能监视每个连接,长时间未连接则认为连接失效,重连
呵呵,解决不了实际问题
“查看以后发现windows任务管理器中的进程的句柄数居然有8000多个”这是在服务器上吗?用第3条,把废连接关掉。
 
OnError时断开连接
 
如果在Onerror中断开的话,我也有顾虑呀,因为Onerror事件发生在连接出问题一段时间后,如果此时我已经做了重连接操作,在Onerror时岂不是又断开了,并非我所愿啊
 
并没有看到free ClientSocket的地方,估计是socket handle没被释放

----------我在Create构造函数中指定了Owner参数,理应由Owner释放才是呀
而且我也试过将Create函数中的Owner参数指定为nil,在每一次的‘脉搏’处理中都动态创建和释放一次ClientSocket一次,可问题依然存在。
 
今天早上我做了更仔细的测试,发现在设计时添加的ClientSocket组件(nonBlocking模式)在连接某未开启的主机时,也会导致句柄数的持续增加,此时的Close函数好像根本不起作用,是否会是ClientSocket组件本身的问题呢?(被Borland弃用的原因?)有没有相关的替代组件可供选择,当然要够稳定哪,最好有使用说明。本来想用indy,但感觉有些不适用。
 
異步方式還是用ICS好一點,當然用API也可以,但我覺得挺麻煩的。INDY不大適合做長期穩定的程序。
到http://www.overbyte.be/frame_index.html去下載ICS的穩定版本吧,我用它的HTTP控件作服務器長期運行,一點事都沒有,自己寫的就會出現或多或少的內存洩漏。
 

Similar threads

S
回复
0
查看
1K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
934
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
顶部