Delphi & Datasnap - Тайм-аут соединения, Тайм-аут связи или способ избежать зависания клиентского приложения при отсутствии ответа сервера

Я пытаюсь использовать архитектуру Client-Server Datasnap. Клиент находится внутри Android-приложения, которое соединяется через Wi-Fi с серверной программой, которая работает на ПК.

Это функции сервера и клиента:

Сторона сервера:

Методы сервера

TSQLConnection

  • Водитель: Жар-птица.
  • KeepConnection: правда.

Контейнер сервера

TDSServer

  • Очередь: 100
  • ChannelresponseTimeout: 3000

TDSTCPServerTransport

  • BufferKBSize: 32
  • KeepAliveEnablement: kaDisabled
  • MaxThreads: 30
  • PoolSize: 10
  • Порт: 211

Сторона клиента

Главный

TSQLConnection

  • Водитель: Datasnap
  • ConnectTimeout: 2000
  • CommunicationTimeOut: 5000
  • Конструктор DBXConnection:

Функция:

function TFrm_Principal.GetServerMethods1Client: TServerMethods1Client;
begin
  Conexion.Close;
  Conexion.Open;
  if FServerMethods1Client = nil then
  begin
    FServerMethods1Client := TServerMethods1Client.Create
      (Conexion.DBXConnection, FInstanceOwner);
  end;
  result := FServerMethods1Client;
end;

ClientClasses

  • Пример команды (который, конечно, имеет свой эквивалент на стороне сервера)

Функция:

function TServerMethods2Client.validaEstado(factura: string): Boolean;
begin
  try
    if FvalidaEstadoCommand = nil then
    begin
      FvalidaEstadoCommand := FDBXConnection.CreateCommand;
      FvalidaEstadoCommand.CommandType := TDBXCommandTypes.DSServerMethod;
      FvalidaEstadoCommand.Text := 'TServerMethods1.validaEstado';
      FvalidaEstadoCommand.Prepare;
    end;
    FvalidaEstadoCommand.CommandTimeout := 3;
    FvalidaEstadoCommand.Parameters[0].Value.SetWideString(factura);
    FvalidaEstadoCommand.ExecuteUpdate;
    Result := FvalidaEstadoCommand.Parameters[1].Value.GetBoolean;
  except
    on e: Exception do
    begin
      controlarError;
    end;
  end;
end;

Все работает очень хорошо и быстро, но когда планшет теряет соединение Wi-Fi с сервером, он зависает дольше времени ожидания, назначенного в разных свойствах. Иногда я жду 30 или 40 секунд, и нет ответа. Если я подхожу ближе к сетевому маршрутизатору, иногда он восстанавливает поток, но если я остаюсь в стороне, приложение, наконец, вылетает. Вопрос в том, почему он зависает, если существуют тайм-ауты, которые заставляют приложение отвечать "невозможно подключиться к сети вовремя" или "ошибка тайм-аута" вместо того, чтобы просто зависать без какой-либо возможности для пользователя, чем ожидание или перезапуск. приложение?

0 ответов

Я еще не использовал Firebird, но использовал TSQLConnectionс DataSnap. Я предполагаю, что Firebird использует те же коммуникационные библиотеки, что иTSQLConnection. Если да, то:

Основополагающие вызовы передали в Windows (то есть, WinSock) и нет не так, что я нашел, чтобы проверить, если соединение не повреждено.

Я написал простую серверную функцию DataSnap под названием CheckCon(), который ничего не делает, кроме того, что дает клиентскому приложению что-то для вызова на сервере, чтобы узнать, подключен ли канал связи. Я поставил клиентский вызов наCheckCon() в try...except блок, чтобы я мог перехватить ошибку и автоматически переподключиться, когда EIdSocketError Поднялся.

Пользователь получает автоматическое переподключение, что полезно, но ему по-прежнему приходится ждать 30 секунд, пока Windows WinSock не истечет, прежде чем он вернет ошибку сокета и выполнится код автопереподключения.

В этой старой ветке есть объяснение от Реми Лебо по аналогичной теме, и, поскольку DataSnap использует Indy, я думаю, что это применимо и здесь:

Вы не сможете своевременно [проверить, подключен ли клиент к серверу]. Indy использует блокирующие сокеты, а блокирующие сокеты просто не предназначены для быстрого обнаружения аномальных отключений. Когда происходит ненормальное отключение, базовая библиотека сокетов (WinSock в Windows, Libc в Linux и т. Д.) Не будет знать, что сокет потерян, до тех пор, пока библиотека не истечет внутреннее время, а затем сделает сокет недействительным. Пока это не произойдет, Indy не сможет узнать, подключен ли сокет на самом деле, потому что сама библиотека не знает.

Другие вопросы по тегам