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 не сможет узнать, подключен ли сокет на самом деле, потому что сама библиотека не знает.