TCP Keep Alive на idHttpServer (сервер) и wininet (клиент)

У меня есть приложение веб-сервера, разработанное с использованием idHttpServer. Когда клиент подключается к моему веб-серверу и по какой-то неизвестной причине отключился (а не изящно отключился), мой веб-сервер не получает уведомления. Я знаю, что это нормальное поведение, но мне нужно знать, когда клиент умирает.

Есть несколько способов сделать это. Я знаю 2 хороших способа:

1 - Реализуйте механизм сердцебиения. Клиентский сокет уведомляет сервер о том, что он все еще жив (требуется некоторая работа и некоторый код, чтобы он работал)

2 - TCP Keep Alive. Этот способ мне нравится больше всего, потому что он требует не слишком много кода и работы. Но у меня есть несколько вопросов по этому поводу.

  • Можно ли использовать это с функциями idHttpServer (для сервера) и wininet (для клиента)?
  • Это действительно работает так, как ожидалось? Я имею в виду, что сервер все время не умирает, когда клиент умирает?
  • У кого-нибудь есть образец установки этого на wininet? (Я думаю, это должно быть установлено на стороне клиента, верно?)
  • Есть ли лучший способ уведомить сервер о том, что клиент мертв (конечно, используя indy и wininet)

ИЗМЕНИТЬ

Я использую Delphi 2010 и последний исходный код Indy10 из их svn.


person Rafael Colucci    schedule 04.05.2011    source источник


Ответы (1)


Если вы используете последнюю версию Indy 10, вы можете использовать метод TIdSocketHandle.SetKeepAliveValues():

procedure SetKeepAliveValues(const AEnabled: Boolean; const ATimeMS, AInterval: Integer);

Например:

procedure TForm1.IdHTTPServer1Connect(AContext: TIdContext);
begin
  // send a keep-alive every 1 second after
  // 5 seconds of inactivity has been detected
  AContext.Binding.SetKeepAliveValues(True, 5000, 1000);
end;

Обратите внимание, что параметры ATimeMS и AInterval поддерживаются только в Windows 2000 и новее.

В противном случае используйте метод TIdSocketHandle.SetSockOpt() напрямую, чтобы вручную включить параметр TCP / IP SO_KEEPALIVE:

procedure TIdSocketHandle.SetSockOpt(ALevel: TIdSocketOptionLevel; AOptName: TIdSocketOption; AOptVal: Integer);

Например:

procedure TForm1.IdHTTPServer1Connect(AContext: TIdContext);
begin
  AContext.Binding.SetSockOpt(Id_SOL_SOCKET, Id_SO_KEEPALIVE, 1);
end;
person Remy Lebeau    schedule 05.05.2011
comment
Сделав это, indy должен вызвать событие OnDisconnect? Если да, то это не работает. Если я отключу сетевой кабель, idHttpServer не вызовет событие OnDisconnect. - person Rafael Colucci; 05.05.2011
comment
OnDisconnect не запускается, пока не будет остановлен поток, владеющий сокетом. Пока ОС не сообщит об ошибках в сокете, Indy не знает, что это неработающее соединение. Не все версии ОС сразу распознают обрыв кабеля как потерянное соединение, поэтому даже при включенных пакетах поддержки активности должно пройти несколько сообщений, прежде чем ОС наконец прекратит попытки. На это нужно время. Затем он начинает сообщать об ошибках сокета, которые Indy может обнаруживать и вызывать исключения при следующем доступе к сокету. Убедитесь, что вы не проглатываете исключения Indy в своем коде, пусть сервер обрабатывает их. - person Remy Lebeau; 06.05.2011