Зависание при потере сетевого соединения
Модератор: Модераторы
Зависание при потере сетевого соединения
Здравствуйте!
Попробуйте провести какой эксперимент.
Создайте новое приложение, новая форма.
Установите подключение к какой либо базе данных (например ADOConnection)
База должна находится удаленно, на соседней машине или на хостинге.
В свойствах в design-time устанавливаем connection:=true - всё ок
Ставим на форму кнопку и таймер.
В таймере выставляем 10 секунд и в обработчике пишем команду halt;
Таймер по умолчанию отключен.
По нажатии на кнопку пишем:
включить таймер, далее сделать любой запрос из базы данных и показать результат на форме.
Всё - этого достаточно для эксперимента.
Запускаем программу (соединение уже установлено). Нажимаем на кнопочку. Раз - появляются результаты запроса и через 10 сек - прога вылетает. Всё отлично.
Теперь вторая попытка, но с небольшим но...
Запускам программу. Теперь вытаскиваем штекер из сетевой карты. Нажимаем на кнопочку. И ВСЁ.... ВИСИМ... Где таймер??? Почему не закрывается программа...
Я понимаю, что соединение прервалось и могут быть какие-то там из-за этого заморочки, но почему таймер не срабатывает? Ведь мы его запустили до того, как начали делать запрос? Почему ВСЁ висит... Причем висит не по какому-то таймауту, а бесконечно...
Пробовал с разными базами, пробовал под Win и под Lin - всё одно...
Что делать? Может кто-то подскажет чего я не понимаю?
Попробуйте провести какой эксперимент.
Создайте новое приложение, новая форма.
Установите подключение к какой либо базе данных (например ADOConnection)
База должна находится удаленно, на соседней машине или на хостинге.
В свойствах в design-time устанавливаем connection:=true - всё ок
Ставим на форму кнопку и таймер.
В таймере выставляем 10 секунд и в обработчике пишем команду halt;
Таймер по умолчанию отключен.
По нажатии на кнопку пишем:
включить таймер, далее сделать любой запрос из базы данных и показать результат на форме.
Всё - этого достаточно для эксперимента.
Запускаем программу (соединение уже установлено). Нажимаем на кнопочку. Раз - появляются результаты запроса и через 10 сек - прога вылетает. Всё отлично.
Теперь вторая попытка, но с небольшим но...
Запускам программу. Теперь вытаскиваем штекер из сетевой карты. Нажимаем на кнопочку. И ВСЁ.... ВИСИМ... Где таймер??? Почему не закрывается программа...
Я понимаю, что соединение прервалось и могут быть какие-то там из-за этого заморочки, но почему таймер не срабатывает? Ведь мы его запустили до того, как начали делать запрос? Почему ВСЁ висит... Причем висит не по какому-то таймауту, а бесконечно...
Пробовал с разными базами, пробовал под Win и под Lin - всё одно...
Что делать? Может кто-то подскажет чего я не понимаю?
Насчет бесконечности зависания в ADOConnection не знаю.
Но само подвисание происходит в процедуре запроса. А форма, обработчик таймера, обработчик кнопок - это все один поток. Поэтому зависание любой процедуры приведет к зависанию всего потока, т.е. пока программа не завершит выполнение обработчика кнопки никакой таймер не сработает.
Но само подвисание происходит в процедуре запроса. А форма, обработчик таймера, обработчик кнопок - это все один поток. Поэтому зависание любой процедуры приведет к зависанию всего потока, т.е. пока программа не завершит выполнение обработчика кнопки никакой таймер не сработает.
может передать timeout в параметрах при подключении?
-
alex208210
- постоялец
- Сообщения: 207
- Зарегистрирован: 12.05.2010 13:16:51
правильно alexey38 написал, нужно разветсти по разным потокам подключение к базе и работу таймера
Выяснил, что ровно через 18 минут срабатывает исключение sql error lost connection...
Почему так долго и где можно изменить это время до 10 секунд.
Я понимаю, что выставляться это должно на клиенте, так как после разрыва сети сервер недоступен...
Помогите разобраться...
Почему так долго и где можно изменить это время до 10 секунд.
Я понимаю, что выставляться это должно на клиенте, так как после разрыва сети сервер недоступен...
Помогите разобраться...
Не знаю как вы коннекитесь к базе, но через ODBC/JDBC есть параметр который задает timeout.
Не знаю как вы коннекитесь к базе, но через ODBC/JDBC есть параметр который задает timeout.
Коннект к базе здесь не причем. Соединение отрабатывает отлично. Если вытащить шнурок и попытаться установить соединение, то вызывается ошибка мгновенно. Но вот если сначала соединиться, а потом вытащить шнурок - после этого запрос из базы вызывает подвисание всей программы на 18 минут и только после этого выскакивает исключение.
Вопрос - где установлены эти 18 минут (а точнее 17 минут и 45 секунд), потому что именно это время висит - проверял несколько раз. Мне достаточно установить его в 3-5 сек и всё.
Различные переменные timeout на сервере менял - ничего не даёт.
Помогите пожалуйста, вторые сутки бьюсь... по всему интернету всё излазил - не могу ничего сделать...
Неужели все так и работают - ведь это неправильно!
Коннект к базе здесь не причем
Очень даже причем. Коннект позволяет задать несколько тайм-аутов. Тайм-аут на коннект и на сокет, к примеру.
Различные переменные timeout на сервере менял - ничего не даёт.
Фигней то маяться зачем? Вы из сервера провод выдрали, как он вам выдаст ошибку по тайм-ауту? Через астрал?
С паскалем я с базой данных не работал. Все больше с JAVA. так у JDBC драйверов есть возможность задать свойство socketTimeout Есть и другие вкусности, например, tcpKeepAlive - булево значение для удержания tcp соединения (ну это нахрен не нужно ващето). Поиск по волшебным словам дает много чего.
http://jdbc.postgresql.org/documentatio ... nnect.html
Также можно задать тайм-аут на SQL запрос.
Код: Выделить всё
Connection conn = DriverManager.getConnection(url, props);
PreparedStatement st = conn.prepareStatement("INSERT INTO test VALUES('xxx')");
st.setQueryTimeout(5);
st.execute();
Когда на форуме по паскалю дают ответ на джаве... Грядет апокалипсис!
Это просто чтоб знал человек куда копать
Подскажите вы решение нашли проблемы?
Я в подобном случае просто засунул обращение к сети в отдельный поток (TThread). 
(Видимо частичное игнорирование таймаута это багофича "Форточек" от 10-ки и выше )
Зы
Простейший вариант "оболочки " над операцией ввода вывода.
( Я в курсе что поток может подвиснуть но это куда меньшее золо чем прога повисшая "с концами" (в принципе есть способы завершить поток принудительно но обычно зависшая операция ввода вывода все-же когда-то завершается ))
(Видимо частичное игнорирование таймаута это багофича "Форточек" от 10-ки и выше )
Зы
Простейший вариант "оболочки " над операцией ввода вывода.
( Я в курсе что поток может подвиснуть но это куда меньшее золо чем прога повисшая "с концами" (в принципе есть способы завершить поток принудительно но обычно зависшая операция ввода вывода все-же когда-то завершается ))
Код: Выделить всё
Type
TLoad_HTML_Thread=Class(TThread)
private
protected
procedure Execute; override;
procedure Load;
procedure SLoad;
public
constructor Create(CreateSuspended: boolean;
URL:String;TOut,RP:Integer;Var RText:String);
public
UPDATE:Boolean;
Err :Boolean;
END_T :Boolean;
fRText:^String;
fURL:String;
IsInternet:Boolean;
fTOut,fRP:Integer;
end;
procedure TLoad_HTML_Thread.Load;
begin
try
Err:=False;
Err:=LoadHTMPageFromURL(fURL,fTOut,fRP,fRText^)<>'OK';
except
Err:=True;
end;
end;
procedure TLoad_HTML_Thread.SLoad;
begin
IsInternet:= IsInternetConnected ;
Err:= not IsInternet;
end;
procedure TLoad_HTML_Thread.Execute;
begin
while (not Terminated) do
If UPDATE then begin
Synchronize(@SLoad);
if IsInternet then Load;
if not End_T then
End_T:=True;
UPDATE :=False;
end;
END_T:=True;
end;
constructor TLoad_HTML_Thread.Create(CreateSuspended: boolean;
URL:String;TOut,RP:Integer;Var RText:String);
begin
END_T:=False;
fUrl:=Url;
fRText:=@Rtext;
fTOut:=TOut;
fRP:=rp;
UPDATE :=False;
inherited Create(CreateSuspended);
end;
Function Thread_LoadHTML(URL:String;
var RS:String;
OutTime:TDateTime=1.0 ):Boolean;
var
NTT:TLoad_HTML_Thread;
Const
CTime:TDateTime=0;
begin
Result:=False;
NTT:=TLoad_HTML_Thread.Create(True, URL,Global_Attempts, RS);
NTT.Start;CTime:=Now;NTT.UPDATE:=true;
While not NTT.End_T do begin
Result:= (now-CTime)*10e4 < OutTime ;
if not Result then break;
Application.ProcessMessages;
end;
if Result then Result := NTT.End_T and (Not NTT.Err);
NTT.FreeOnTerminate:=true;
NTT.Terminate;
end
Последний раз редактировалось Alex2013 01.06.2023 11:26:15, всего редактировалось 1 раз.
У меня такая идея тоже есть. Потоки то когда нибудь отвиснут (восстановится соединение или закончится таймер (у меня время таймера 15,5 минут))и их можно будет завершить. Я думаю это не проблема.
Но возникает ситуация, если программа сложная и таких параллельных подзапросов достаточно много, то сколько я могу наплодить подвисших потоков. Неужели нет возможности установить таймер сброса подключения вручную.
Добавлено спустя 1 час 32 минуты 25 секунд:
Походу я нашел ответ, по крайней мере в моем случае. Только объяснить его не могу.
AstraLinux
параметр tcp_retries2 по умолчанию стоит = 15, установил = 1, обрыв происходит практически мгновенно при разрыве соединения.
команда
sudo sysctl -w net.ipv4.tcp_retries2=1
Но возникает ситуация, если программа сложная и таких параллельных подзапросов достаточно много, то сколько я могу наплодить подвисших потоков. Неужели нет возможности установить таймер сброса подключения вручную.
Добавлено спустя 1 час 32 минуты 25 секунд:
Походу я нашел ответ, по крайней мере в моем случае. Только объяснить его не могу.
AstraLinux
параметр tcp_retries2 по умолчанию стоит = 15, установил = 1, обрыв происходит практически мгновенно при разрыве соединения.
команда
sudo sysctl -w net.ipv4.tcp_retries2=1
В принципе количество потоков не особо ограничено ( в моей программе их иногда за сотню ) сами потоки много места в памяти не занимают + подвисание происходит за пределами программы что по идее означает что рано или поздно "не обслуженный" запрос будет прибит на уровне системы. Ну и само собой все запущенные потоки убиваются при завершении программы ( то есть при случае особо тяжелой утечки памяти или лаге можно банально автоматически перезапустить программу )Xaoc писал(а):Но возникает ситуация, если программа сложная и таких параллельных подзапросов достаточно много, то сколько я могу наплодить подвисших потоков.
Добавлено спустя 13 минут 3 секунды:
Возможно есть, но скорее всего работает это для каждого конкретного типа операций ввода вывода по разному.Xaoc писал(а): Неужели нет возможности установить таймер сброса подключения вручную.
...и беда не в том что нельзя установить значение таймаута а в том что иногда повисает "сам таймаут".
