Страница 1 из 1

Firebird connection timeout [Решено]

СообщениеДобавлено: 20.01.2018 19:55:19
lordgray
Здравствуйте!
Проблема в следующем: есть сервер, на нем Firebird 2.5.7. К нему будет программа подключаться через интернет. Все работает, всем доволен. Но, если вдруг сервер недоступен (проблемы у провайдера, нет электроэнергии, ...), программа зависает на 4 минуты. Т.е. клиент ждет ответа от сервера. Начал копать интернет на предмет уменьшения времени ожидания, и везде пишут о константе "connect_timeout=...". Вот тут и начинаются проблемы.
Код: Выделить всё
FIBDatabase.DBParams.Append('connect_timeout=5')

дает ошибку "DPB Constant (isc_dpb_connect_timeout) is unsupported"
пробовал и "connecttimeout=5"
дает ошибку "DPB Constant (0) is unsupported"

Кто-то решал такую проблему? Как уменьшить время ожидания?

Даже пробовал через поток, но что толку, виснет поток, и прога не закрывается, пока в потоке не придет через 4 минуты таймаут.
Что делать?

Re: Firebird connection timeout

СообщениеДобавлено: 20.01.2018 21:35:59
*Rik*
Судя по ответу сервера отключили его использование... Наверно на стороне сервера CONNECTION_TIMEOUT в конфиге крутить надо...

Re: Firebird connection timeout

СообщениеДобавлено: 20.01.2018 21:41:42
lordgray
*Rik* писал(а):Наверно на стороне сервера CONNECTION_TIMEOUT в конфиге крутить надо...

А толку, если сервер клиенту недоступен?

Я так понимаю, что, если задать время таймаута нельзя, то остаются только потоки. Но, как остановить поток корректно, без AV, тоже в интернете не нашел

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 00:30:30
olegy123
lordgray писал(а):connect_timeout
Пишут про отключение клиента со стороны сервера если он не активен.

Тут видно два пути:
1) колдовать с параметрами TCP стека, именно они ждут ответа а с ними ждет клиент FB.
2) самим учитывать время подключение.. вешать "watch dog" по таймеру, если за отведенное время не произошло подключение. То принудительно завершать само потключение. Или сигналить о превышении времени.

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 17:24:30
lordgray
olegy123 писал(а):самим учитывать время подключение.. вешать "watch dog" по таймеру, если за отведенное время не произошло подключение. То принудительно завершать само потключение.

Это понятно. Но как?

Ну, сделал я потомка TThread, в Execute вызываю Database.Open, и поток уходит в ожидание. Все это я делаю для обновления клиентской базы. Если пользователь "долго" работает, то нет проблем, возникнет таймаут, и я убью поток. Но если пользователь решил закрыть программу? Ничего не происходит, т.к. поток висит. Очевидно, что вызов Terminate ничего не дает, т.к. он только ставит соответствующее свойство в True. Пробовал Suspend + Free, получаю AV. Как корректно остановить поток? Ведь масса браузеров, торрентов, загрузчиков делают это.

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 18:07:02
iskander
на правах кэпа:
обычно тело Execute завернуто в цикл
Код: Выделить всё
  while not Terminated do
    begin
      ...
    end;

в Вашем случае это возможно
Код: Выделить всё
  while not Terminated and not Database.Connected do
    begin
      Database.Open;
      Sleep(...);
    end;

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 18:47:52
lordgray
iskander писал(а):while not Terminated and not Database.Connected do
Database.Open;


Вот это ничего не дает, уже так делал, т.к. на Database.Open поток зависнет на 4 минуты, и до проверки на Terminated и Connected дойдет тоже через 4 минуты. Соответственно, толку, что я в OnClose главной формы вызову Terminate, если он проверится, когда придет таймаут (и поток и так завершится по try...finally)

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 19:20:06
iskander
Прошу прощения, невнимательно читал тред :oops: .
Ничего лучше чем сканировать удаленный порт в голову не приходит :( .

Re: Firebird connection timeout

СообщениеДобавлено: 21.01.2018 20:02:26
lordgray
iskander писал(а):Ничего лучше чем сканировать удаленный порт в голову не приходит :(


Была такая мысль. Да, частично решает проблему, и если ничего лучше не найдется, остановлюсь на этом.

Re: Firebird connection timeout

СообщениеДобавлено: 22.01.2018 11:08:04
olegy123
olegy123 писал(а):1) колдовать с параметрами TCP стека, именно они ждут ответа а с ними ждет клиент FB.

http://www.ibase.ru/keepalive/

Добавлено спустя 3 минуты 58 секунд:
lordgray писал(а):
olegy123 писал(а):самим учитывать время подключение.. вешать "watch dog" по таймеру, если за отведенное время не произошло подключение. То принудительно завершать само потключение.

Это понятно. Но как?

Ну, сделал я потомка TThread, в Execute вызываю Database.Open, и поток уходит в ожидание. Все это я делаю для обновления клиентской базы. Если пользователь "долго" работает, то нет проблем, возникнет таймаут, и я убью поток. Но если пользователь решил закрыть программу? Ничего не происходит, т.к. поток висит. Очевидно, что вызов Terminate ничего не дает, т.к. он только ставит соответствующее свойство в True. Пробовал Suspend + Free, получаю AV. Как корректно остановить поток? Ведь масса браузеров, торрентов, загрузчиков делают это.


"watch dog" - это отдельный таймер, который запускается и ждет заданное время, после срабатывает. Вот когда он срабатывает, можно проверять состояние системы. Если ничего не изменилось, флаги не поменялись - система "подвисла".
Для "watch dog" вполне подойдет даже отдельный TTimer.

Re: Firebird connection timeout

СообщениеДобавлено: 22.01.2018 13:21:14
lordgray
Почитал про KEEPALIVE. То ли я чего-то не понял, то ли Вы меня не поняли. Чем мне может помочь KEEPALIVE? Через него СЕРВЕР определяет доступность клиента, при чем, УЖЕ УСТАНОВЛЕННОГО соединения. А мне надо наоборот. Кроме того, настройки влияют на всю операционку! Как такое можно требовать от клиентов? Может они не хотят менять эти настройки, тем более, что в статье написано, что иногда изменения приводят к проблемам в некоторых программа. Короче, по моему это вообще не с той оперы.

По WatchDog. Проблема не в том, как его реализовать (хоть таймер, хоть поток, хоть OnIdle), а ЧТО ДЕЛАТЬ, если определил, что Database.Open завис.

Еще раз. Пользователь запустил программу. Она открывает локальную базу, и пользователь с ней работает. Помимо этого, стартует поток, в котором идет подключение к удаленной базе, для обновления локальной. И проблема возникает в том случае, если таймаут еще не настал, а пользователь закрывает программу.
В этом случае программа не закрывается, т.к. есть работающий поток, а зависает. И что делать? Terminate потока бесполезен, Free хоть потока, хоть Database, приводит к Acces Violation. Неужели нет способа, корректно остановить поток и удалить его?

Re: Firebird connection timeout

СообщениеДобавлено: 22.01.2018 18:39:23
olegy123
Как вы думает устроен интернет? Как реализован TCP подключение?
Неужели добрый Волшебник своей волшебной палочкой касается одной сетевухи и другой - образуется линк? А злой волшебник рвет ножницами.. из-за этого у lordgray зависает приложение?
KEEPALIVE - нужны для определения „Ще не вмерл" ваш линк. Это и "есть пинги" до другого хоста.. Другой хост отвалился или машрут нарушился - так на уровне OS система узнает о живости сообщений. Как долго будет ждать, сколько пингов нужно послать чтобы определить об нарушений свзяи - делается этими параметрами.

lordgray писал(а):а ЧТО ДЕЛАТЬ, если определил, что Database.Open завис.
дисконнектить и фрешить. Ровно так же как устроен проигрыватель фильмов - Что делать если я фильм закрыл.. играть до конца?

lordgray писал(а):Она открывает локальную базу, и пользователь с ней работает. Помимо этого, стартует поток, в котором идет подключение к удаленной базе, для обновления локальной. И проблема возникает в том случае, если таймаут еще не настал, а пользователь закрывает программу.
Вот вы едете на авто, тут "вити надо выйти".. Начинаете сигналить правым фанарем, прижимаетесь к обочине сбрасываете скорость..
Дисконектить подключение в отдельном потоке.

lordgray писал(а):В этом случае программа не закрывается, т.к. есть работающий поток, а зависает. И что делать? Terminate потока бесполезен, Free хоть потока, хоть Database, приводит к Acces Violation.
Естественно, как "вити надо выйти" при скорости в 150км/ч? При Terminate вы катапультируете..

Зачем вам отдельный поток? для каких целей? С отдельным потоком нужно уметь работать. Тут вам не Java где object=NULL все дискрипторы за вас закроют, трейды затушат. Тут нужно самим тушить все открытые хендлы и освобождать выделенные рессурсы..

lordgray писал(а):Неужели нет способа, корректно остановить поток и удалить его?
Есть. Просто термитить трейд этого мало.

Re: Firebird connection timeout

СообщениеДобавлено: 22.01.2018 22:21:57
lordgray
olegy123 писал(а):KEEPALIVE - нужны для определения „Ще не вмерл" ваш линк

На данном этапе, мне не интересно, умер коннект или нет, так как коннект просто не удается установить. И кроме того, KEEPALIVE явно не равен 4 минутам, которые ждет клиент Firebird. Тем более, пробовал как на Линуксе, так и под Виндой.
olegy123 писал(а):Дисконектить подключение в отдельном потоке.

Как можно дисконнектить то, что еще незаконнекчено?
olegy123 писал(а):Зачем вам отдельный поток? для каких целей?

Для фонового обновления базы. Например, как антивирусы обновляют свои базы.
olegy123 писал(а):Есть. Просто термитить трейд этого мало.

Да я вижу, что мало, уже напробовался. Вот только, что нужно сделать, чтоб было достаточно?

Re: Firebird connection timeout

СообщениеДобавлено: 23.01.2018 03:53:14
olegy123
lordgray писал(а):На данном этапе, мне не интересно, умер коннект или нет, так как коннект просто не удается установить.

lordgray писал(а):Но, если вдруг сервер недоступен (проблемы у провайдера, нет электроэнергии, ...), программа зависает на 4 минуты. Т.е. клиент ждет ответа от сервера. Начал копать интернет на предмет уменьшения времени ожидания, и везде пишут о константе "connect_timeout=...". Вот тут и начинаются проблемы.
так начинаются ли проблемы с зависанием или нет?
параметр KEEPALIVE нужен оси, таким образом она определяет, когда сендить ерорку вашей проги, мол контакт потерян.

lordgray писал(а):Как можно дисконнектить то, что еще незаконнекчено?
Когда переводишь в контак что происходит? А происходит то, что либла начинает работать над тем чтобы подготовить работу с БД, готовит буфера, хендлы, открывает сокеты.. Это еще незаконеченно!!! переходит в ожидание ответа от севера..Это еще незаконеченно!!!
Хост получает пакет, начинает думать кто это? Может куча фильтров сработать, может куча пересылок пройти..Это еще незаконеченно!!! пакет дошел до FB, ФБ начинает отвечать твоей лилбе..
Сколько времени прошло? меньше 1ms или больше 4минуты? А за это время может случится разрыв https://www.youtube.com/watch?v=BsjAzOGe0cI
что делать клиенту?

Добавлено спустя 14 минут 45 секунд:
lordgray писал(а):Вот только, что нужно сделать, чтоб было достаточно?
ну если еще до того как сокет будет открыт и еще нужный пакет не ушел на сторону ФБ по проводам.. а уже проделана большая работа: выделена память в ОЗУ, классы построены, готовятся перейти в длительное ожидание.. и тут клиент жмет стоп-кран..

Re: Firebird connection timeout

СообщениеДобавлено: 02.02.2018 14:08:05
lordgray
Все, решил!
Длительность ожидания коннекта не совсем зависит от FireBird. Он просто делает несколько попыток, а вот сколько тянется одна попытка, зависит от настроек сети. Поскольку, заставлять пользователя перенастраивать сеть, или менять программно самому - некорректно, идем другим путем, через асинхронные сокеты, пытаемся установить коннект с сервером. Самому серверу Firebird, это безвредно, т.к. передавать ничего не будем. Асинхронные сокеты нужны для того, чтобы ожидание коннекта можно было прервать в любой момент.
Попытался с наскоку сам их программировать, но, не имея опыта в работе с сокетами вообще, и асинхронными в частности, через пару дней отказался от этого, и решил использовать компоненты http://wiki.lazarus.freepascal.org/lNet, т.к. легкие (а мне кроме установки коннекта, ничего больше и не надо), кроссплатформенные и работают на асинхронных сокетах.

Код: Выделить всё
uses lnet;
...
procedure TMyThread.Execute;
const
  timeout = 3000;//in miliseconds
  srv_ip = '192.168.1.75';
var
  TCP: TLTCP;
  t: QWord;
begin
  TCP := TLTCP.Create(nil);
  try
    t := GetTickCount64;
    if TCP.Connect(srv_ip, 3050) then//IP & Port Firebird server
    repeat
      TCP.CallAction;//wait OnConnect
    until TCP.Connected or Terminated or (GetTickCount64 - t > timeout);
    if TCP.Connected and (not Terminated) then
    begin
      TCP.Disconnect;
      DB.DatabaseName := srv_ip + ':/home/sergey/database.fdb';
      DB.Open;
      ...
    end;
  finally
    if Assigned(TCP) then TCP.Free;
  end;
end;


Все! У меня работает, я доволен, тема закрыта