Как определить, жива ли связь с Инди? - PullRequest
4 голосов
/ 11 сентября 2009

Я использую 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.

Что здесь происходит? Как я могу избежать попыток отправки с использованием разорванных соединений?

Ответы [ 2 ]

5 голосов
/ 11 сентября 2009

Хорошо, я нашел решение. Вместо хранения 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;          

Это работает для меня.

2 голосов
/ 11 сентября 2009

Если клиент закрывает соединение, клиентский компьютер / сетевая карта умирает или у вас возникли какие-либо другие проблемы с сетью между вами и клиентом, вы можете не знать об этом до следующей попытки записи в соединение.

Вы можете использовать сердцебиение. Время от времени отправляйте клиенту сообщение с коротким тайм-аутом, чтобы проверить, все ли соединение действительно. Таким образом, вы будете знать раньше, если произошел неожиданный разрыв соединения. Вы можете обернуть его в функцию «CheckConnection» и вызвать его перед отправкой ответа.

...