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;
现将代码罗列如下:
动态生成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;