Как определить, все еще живо соединение с Indy?

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

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


person jpfollenius    schedule 11.09.2009    source источник


Ответы (2)


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

Это подходит для меня.

person jpfollenius    schedule 11.09.2009

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

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

person Bruce McGee    schedule 11.09.2009
comment
Проблема в том, что доступ к TIdContext и соединению приводит к остановке приложения - сообщение о тестовом соединении не имеет значения. - person jpfollenius; 11.09.2009
comment
Он зависает, потому что ждет тайм-аута? - person Bruce McGee; 11.09.2009
comment
Indy блокирует, так что, вероятно, приложение останавливается на этом. Лучший способ проверить, жив ли клиент, - это прослушать сообщения о состоянии клиента. Клиент должен проходить регистрацию через регулярные промежутки времени. Если клиент пропустит много таких проверок, вы можете считать его недоступным. Или вы можете использовать неблокирующую библиотеку (ICS), чтобы ваше приложение не блокировало TCP-соединения. И разработайте приложение таким образом, чтобы ожидание соединения не означало, что приложение не отвечает. Используйте неблокирующие сокеты или потоки. - person Runner; 11.09.2009
comment
Я использую потоки для общения с клиентом, но, к сожалению, зависает все приложение, а не только поток общения. - person jpfollenius; 12.09.2009