4

我使用 Indy 进行 TCP 通信(D2009,Indy 10)。

在评估客户请求后,我想将答案发送给客户。因此,我像这样存储 TIdContext(伪代码)

procedure ConnectionManager.OnIncomingRequest (Context : TIdContext);
begin
  Task := TTask.Create;
  Task.Context := Context;
  ThreadPool.AddTask (Task);
end;

procedure ThreadPool.Execute (Task : TTask);
begin
  // Perform some computation
  Context.Connection.IOHandler.Write ('Response');
end;

但是,如果客户端在请求和准备发送的答案之间的某个地方终止连接怎么办?如何检查上下文是否仍然有效?我试过

if Assigned (Context) and Assigned (Context.Connection) and Context.Connection.Connected then
  Context.Connection.IOHandler.Write ('Response');

但这无济于事。在某些情况下,程序只是挂起,如果我暂停执行,我可以看到当前行是带有 if 条件的行。

这里会发生什么?如何避免尝试使用死连接发送?

4

2 回答 2

5

好的,我找到了解决方案。我没有存储 TIdContext,而是使用 TIdTcpServer 提供的上下文列表:

procedure ThreadPool.Execute (Task : TTask);
var
  ContextList : TList;
  Context : TIdContext;
  FoundContext : Boolean;
begin
  // Perform some computation

  FoundContext := False;
  ContextList := FIdTCPServer.Contexts.LockList;
  try
    for I := 0 to ContextList.Count-1 do
      begin
      Context := TObject (ContextList [I]) as TIdContext;
      if (Context.Connection.Socket.Binding.PeerIP = Task.ClientInfo.IP) and
         (Context.Connection.Socket.Binding.PeerPort = Task.ClientInfo.Port) then
        begin
        FoundContext := True;
        Break;
        end;
      end;
  finally
    FIdTCPServer.Contexts.UnlockList;
  end;

  if not FoundContext then
    Exit;

  // Context is a valid connection, send the answer

end;          

这对我行得通。

于 2009-09-11T14:41:41.383 回答
2

如果客户端关闭连接,客户端机器/网卡死机,或者您和客户端之间存在其他网络问题,您可能直到下次尝试写入连接时才知道它。

你可以使用心跳。偶尔给客户端发送一个短超时的消息,看看连接是否仍然有效。这样,您会更快地知道是否发生了意外断开连接。您可以将其包装在“CheckConnection”函数中并在发送响应之前调用它。

于 2009-09-11T12:42:50.253 回答