Delphi 失效的TCP连接

Delphi 失效的TCP连接,delphi,tcp,indy,Delphi,Tcp,Indy,我在Windows服务应用程序中使用Indy10和Delphi XE,其中TIdCmdTCPServer使用TIdTCPClient为客户端提供服务 具有此功能 function ConnectionCount: Integer; begin if IdCmdTCPServer.Contexts = nil then Exit(0); with IdCmdTCPServer.Contexts do try Result := LockList.Count fina

我在Windows服务应用程序中使用Indy10和Delphi XE,其中TIdCmdTCPServer使用TIdTCPClient为客户端提供服务

具有此功能

function ConnectionCount: Integer;
begin
  if IdCmdTCPServer.Contexts = nil then
    Exit(0);
  with IdCmdTCPServer.Contexts do
  try
    Result := LockList.Count
  finally
    UnlockList
  end;
end;
我得到了从客户端到服务器的连接数。有时,即使所有客户端都已关闭,此计数也不会降至零。我想这些联系不知怎么的已经消失了。在一个有5个客户端的站点上,经过几周的运行,我看到连接数达到35

有没有办法检测到连接已断开并将其释放

我怀疑如果客户端冻结或被杀死,连接可能会死掉,但我不知道这里的情况是否如此

编辑:以下是我的一个TIdCmdTCPServer处理程序中的代码:

procedure TDSA_Service.ModeHandler(ASender: TIdCommand);
var
  R: TToolReply;
begin
  FBMutex.Enter;
  try
    try
      R := SystemServer.Mode(GetIntParam(0, 'SystemNo', ASender));
      try
        Reply(ASender, R)
      finally
        R.Free
      end
    except
      HandleException;
      Abort
    end
  finally
    FBMutex.Leave
  end
end;

除发送错误报告外,将生成HandleException。一些印第例外情况不应该在这里被发现,我说得对吗?哪些例外情况?

您无法真正确定连接是否“失效”。我要做的是确定连接是否存在超过24小时的时间,如果存在,则将其删除。 我不在乎雷米提出的“为什么联系总是存在”的问题。我的用户也不介意他们第二天早上来时发现他们的客户不再响应。我希望这段代码能回答更多的问题

type
  TClientData = class(TObject)
    ClientName: string;
    ClientHost: string;
    ID: TDateTime;
  end;

type
  TDateTimeO = Class(TObject)
public
  Value: TDateTime;
  constructor Create(NewValue: TDateTime);
end;

const
  MAXCONNECT = (24 * 60 * 60);

procedure TfrmMain.IdCmdTCPServer1Connect(AContext: TIdContext);
var
  myClient: TClientData;
begin
  AContext.Connection.IOHandler.DefStringEncoding := IdGlobal.IndyTextEncoding_8Bit;
  myClient := TClientData(AContext.Data);
  if myClient = nil then
  begin
     myClient := TClientData.Create;
     AContext.Data := myClient;
     myClient.ClientName := '<Unknown>';
     myClient.ClientHost := AContext.Binding.PeerIP;
     myClient.ID := Now;
  end;
  // this actually happens elsewhere in my server code, but I've pasted
  // it here for convenience
  ListBox1.Items.AddObject(
    myClient.ClientName + '=' +
    FormatDateTime('yyyy-mm-dd hh:nn:ss', myClient.ID),
    TDateTimeO.Create(myClient.ID));

end;

procedure TfrmMain.Timer1Timer(Sender: TObject);
var
  ThisMoment: TDateTime;
  i, j: Integer;
  List: TList;
  Name: String;
  TimeStamp: TDateTime;
  MyClient: TClientData;
begin

  ThisMoment := Now;
  List := IdCmdTCPServer1.Contexts.LockList;
  try
    for i := ListBox1.Count - 1 downto 0 do
    begin
      // now terminate the actual connection (if it can be found)
      Name := Trim(TokenStr('=', ListBox1.Items[i], 1));
      TimeStamp := TDateTimeO(ListBox1.Items.Objects[i]).Value;
      if (SecondsBetween(TimeStamp, ThisMoment) > MAXCONNECT)
      then
      begin
        for j := List.Count - 1 downto 0 do
        begin
          if Assigned(List[j]) then
          begin
            // is this the corresponding connection?
            myClient := TClientData(TIdContext(List[j]).Data);
            if (Name = myClient.ClientName) and
              (TDateTimeO(ListBox1.Items.Objects[i]).Value = myClient.ID) then
            begin
              TIdContext(List[j]).Connection.Disconnect;
              BREAK;
            end;
          end;
        end; // next j
        // sometimes the connection isn't in the locklist for some reason
        // delete the listbox entry anyway
        TDateTimeO(ListBox1.Items.Objects[i]).Free;
        ListBox1.Items.Delete(i); // and delete the list entry
      end;
    end; // next i
  finally
    IdCmdTCPServer1.Contexts.UnLockList;
  end;

end;
类型
TClientData=类(ToObject)
ClientName:string;
ClientHost:字符串;
ID:TDateTime;
结束;
类型
TDateTimeO=类(TObject)
公众的
值:TDateTime;
构造函数创建(NewValue:TDateTime);
结束;
常数
MAXCONNECT=(24*60*60);
过程TfrmMain.IdCmdTCPServer1Connect(AContext:TIdContext);
变量
我的客户:TClientData;
开始
AContext.Connection.IOHandler.DefStringEncoding:=IdGlobal.IndytextEncoding8bit;
myClient:=TClientData(AContext.Data);
如果myClient=nil,则
开始
myClient:=TClientData.Create;
AContext.Data:=myClient;
myClient.ClientName:='';
myClient.ClientHost:=AContext.Binding.PeerIP;
myClient.ID:=现在;
结束;
//这实际上发生在我的服务器代码的其他地方,但我已经粘贴了
//它在这里是为了方便
ListBox1.Items.AddObject(
myClient.ClientName+'='+
FormatDateTime('yyyy-mm-dd hh:nn:ss',myClient.ID),
TDateTimeO.Create(myClient.ID));
结束;
程序TfrmMain.Timer1Timer(发送方:TObject);
变量
此时此刻:TDateTime;
i、 j:整数;
名单:TList ;;
名称:字符串;
时间戳:TDateTime;
我的客户:TClientData;
开始
此刻:=现在;
列表:=IdCmdTCPServer1.Contexts.LockList;
尝试
对于i:=ListBox1.Count-1到0
开始
//现在终止实际连接(如果可以找到)
名称:=Trim(TokenStr('=',ListBox1.Items[i],1));
时间戳:=TDateTimeO(ListBox1.Items.Objects[i])值;
if(秒之间(时间戳,此时刻)>MAXCONNECT)
然后
开始
对于j:=List.Count-1到0
开始
如果分配(列表[j]),则
开始
//这是对应的连接吗?
myClient:=TClientData(TIdContext(List[j]).Data);
如果(Name=myClient.ClientName)和
(TDateTimeO(ListBox1.Items.Objects[i]).Value=myClient.ID)然后
开始
TIdContext(列表[j])。连接。断开连接;
打破
结束;
结束;
完下一个j
//有时由于某种原因,连接不在锁定列表中
//仍要删除列表框条目
TDateTimeO(ListBox1.Items.Objects[i]).Free;
列表框1.项目。删除(i);//然后删除列表条目
结束;
完接下来我
最后
IdCmdTCPServer1.Contexts.UnLockList;
结束;
结束;

您无法真正确定连接是否“已断开”。我要做的是确定连接是否存在超过24小时的时间,如果存在,则将其删除。 我不在乎雷米提出的“为什么联系总是存在”的问题。我的用户也不介意他们第二天早上来时发现他们的客户不再响应。我希望这段代码能回答更多的问题

type
  TClientData = class(TObject)
    ClientName: string;
    ClientHost: string;
    ID: TDateTime;
  end;

type
  TDateTimeO = Class(TObject)
public
  Value: TDateTime;
  constructor Create(NewValue: TDateTime);
end;

const
  MAXCONNECT = (24 * 60 * 60);

procedure TfrmMain.IdCmdTCPServer1Connect(AContext: TIdContext);
var
  myClient: TClientData;
begin
  AContext.Connection.IOHandler.DefStringEncoding := IdGlobal.IndyTextEncoding_8Bit;
  myClient := TClientData(AContext.Data);
  if myClient = nil then
  begin
     myClient := TClientData.Create;
     AContext.Data := myClient;
     myClient.ClientName := '<Unknown>';
     myClient.ClientHost := AContext.Binding.PeerIP;
     myClient.ID := Now;
  end;
  // this actually happens elsewhere in my server code, but I've pasted
  // it here for convenience
  ListBox1.Items.AddObject(
    myClient.ClientName + '=' +
    FormatDateTime('yyyy-mm-dd hh:nn:ss', myClient.ID),
    TDateTimeO.Create(myClient.ID));

end;

procedure TfrmMain.Timer1Timer(Sender: TObject);
var
  ThisMoment: TDateTime;
  i, j: Integer;
  List: TList;
  Name: String;
  TimeStamp: TDateTime;
  MyClient: TClientData;
begin

  ThisMoment := Now;
  List := IdCmdTCPServer1.Contexts.LockList;
  try
    for i := ListBox1.Count - 1 downto 0 do
    begin
      // now terminate the actual connection (if it can be found)
      Name := Trim(TokenStr('=', ListBox1.Items[i], 1));
      TimeStamp := TDateTimeO(ListBox1.Items.Objects[i]).Value;
      if (SecondsBetween(TimeStamp, ThisMoment) > MAXCONNECT)
      then
      begin
        for j := List.Count - 1 downto 0 do
        begin
          if Assigned(List[j]) then
          begin
            // is this the corresponding connection?
            myClient := TClientData(TIdContext(List[j]).Data);
            if (Name = myClient.ClientName) and
              (TDateTimeO(ListBox1.Items.Objects[i]).Value = myClient.ID) then
            begin
              TIdContext(List[j]).Connection.Disconnect;
              BREAK;
            end;
          end;
        end; // next j
        // sometimes the connection isn't in the locklist for some reason
        // delete the listbox entry anyway
        TDateTimeO(ListBox1.Items.Objects[i]).Free;
        ListBox1.Items.Delete(i); // and delete the list entry
      end;
    end; // next i
  finally
    IdCmdTCPServer1.Contexts.UnLockList;
  end;

end;
类型
TClientData=类(ToObject)
ClientName:string;
ClientHost:字符串;
ID:TDateTime;
结束;
类型
TDateTimeO=类(TObject)
公众的
值:TDateTime;
构造函数创建(NewValue:TDateTime);
结束;
常数
MAXCONNECT=(24*60*60);
过程TfrmMain.IdCmdTCPServer1Connect(AContext:TIdContext);
变量
我的客户:TClientData;
开始
AContext.Connection.IOHandler.DefStringEncoding:=IdGlobal.IndytextEncoding8bit;
myClient:=TClientData(AContext.Data);
如果myClient=nil,则
开始
myClient:=TClientData.Create;
AContext.Data:=myClient;
myClient.ClientName:='';
myClient.ClientHost:=AContext.Binding.PeerIP;
myClient.ID:=现在;
结束;
//这实际上发生在我的服务器代码的其他地方,但我已经粘贴了
//它在这里是为了方便
ListBox1.Items.AddObject(
myClient.ClientName+'='+
FormatDateTime('yyyy-mm-dd hh:nn:ss',myClient.ID),
TDateTimeO.Create(myClient.ID));
结束;
程序TfrmMain.Timer1Timer(发送方:TObject);
变量
此时此刻:TDateTime;
i、 j:整数;
名单:TList ;;
名称:字符串;
时间戳:TDateTime;
我的客户:TClientData;
开始
此刻:=现在;
列表:=IdCmdTCPServer1.Contexts.LockList;
尝试
对于i:=ListBox1.Count-1到0
开始
//现在终止实际连接(如果可以找到)
名称:=Trim(TokenStr('=',ListBox1.Items[i],1));
时间戳:=TDateTimeO(ListBox1.Items.Objects[i])值;
if(秒之间(时间戳,此时刻)>MAXCONNECT)
然后
开始
对于j:=List.Count-1到0
开始
如果分配(列表[j]),则
开始
//这是对应的连接吗?
myClient:=TClientData(TIdContext(List[j]).Data);
如果(Name=myClient.ClientName)和
(TDateTimeO(ListBox1.Items.Objects[i]).Value=myClient.ID)然后