Форум: "Прочее";
Текущий архив: 2007.05.13;
Скачать: [xml.tar.bz2];
ВнизВопрос по энергосбережению и экранной заставке. Проблема. Найти похожие ветки
← →
DVM © (2007-04-16 10:54) [0]Есть программа, которая постоянно должна работать в фоновом режиме. Кратко: принимает данные по сети и пишет файл. Компьютер не трогается некоторое время - появляется заставка. И все... Обмен данными прекращается. Соединение не разрывается, но функция Select возвращает всегда ошибку и все. Как только заставка убирается работа возобновляется. WinXPSP2. В параметрах энергосбережения указано "Включен постоянно".
Прием данных ведется во вторичном потоке.
В чем может быть проблема?
← →
Сергей М. © (2007-04-16 11:04) [1]
> ошибку и все
Что это за ошибка "и все" ?)
← →
DVM © (2007-04-16 11:19) [2]
> Что это за ошибка
select возвращает SOCKET_ERROR, по сведениям WSAGetLastError это
WSAENOTSOCK
← →
Чапаев © (2007-04-16 11:20) [3]> > ошибку и все
> Что это за ошибка "и все" ?)
Это не ошибка "и все", а вместе с ошибкой возвращается ВСЁ.
"-- О! -- сказал Остап. -- Там внутри есть все: пальмы,
девушки, голубые экспрессы, синее море, белый пароход, мало
поношенный смокинг, лакей-японец, собственный бильярд,
платиновые зубы, целые носки, обеды на чистом животном масле и,
главное, мои маленькие друзья, слава н власть, которую дают
деньги. И он раскрыл перед изумленными антилоповцами пустую
папку."
← →
DVM © (2007-04-16 11:26) [4]
> Чапаев © (16.04.07 11:20) [3]
Есть что сказать по делу? Зачитывать описание ошибки из MSDN не требуется.
Может играет роль а может и нет, но поток создается с FThread.Priority := tpLower;
← →
Чапаев © (2007-04-16 11:26) [5]> [4] DVM © (16.04.07 11:26)
Так ведь конференция "Прочее", а не "Сети".
← →
Чапаев © (2007-04-16 11:29) [6]Вообще думается, что-то с рабочими станциями и десктопами связано. Программа эта не сервис случайно?
← →
DVM © (2007-04-16 11:29) [7]
> Чапаев © (16.04.07 11:26) [5]
Тут не совсем по сетям. Работа программы приостанавливается как бы при появлении заставки. Или вторичные потоки приостанавливаются что-ли.
← →
DVM © (2007-04-16 11:30) [8]
> Программа эта не сервис случайно?
Нет не сервис. Хотя сервисом ей быть не помешало бы:).
← →
DVM © (2007-04-16 11:37) [9]с Select разобрался - это сам сервер разрывает соединение, потому как клиент бездействует. Но вот почему поток с клиентом бездействует при включенной заставке - ВОПРОС!
← →
SlymRO © (2007-04-16 11:44) [10]В Outpost имеется галочка "Блокировать весь сетевой трафик при активации программы заставки" :)
← →
DVM © (2007-04-16 11:58) [11]
> SlymRO © (16.04.07 11:44) [10]
Outpost не установлен, установлен, но выключен KAV6 + включен встроенный файерволл.
← →
Сергей М. © (2007-04-16 12:09) [12]
> DVM © (16.04.07 10:54)
WSAAsyncSelect используется ?
← →
DVM © (2007-04-16 12:15) [13]
> WSAAsyncSelect используется
нет.
← →
Сергей М. © (2007-04-16 12:25) [14]
> DVM © (16.04.07 12:15) [13]
Каким образом твой транспорт завязан на оконные сообщения ?
← →
DVM © (2007-04-16 12:32) [15]
> Сергей М. © (16.04.07 12:25) [14]
Во вторичном потоке чтение происходит так:
function TInputThread.ReadData(ABuffer: TBuffer; BytesExpected: integer): integer;
const
MaxLen = 262144;
var
TotalBytesToRead, Found, TotalBytesRead, BytesToRead, BytesRead: integer;
Rfds: TFDSet;
TempBuff: array [0..Pred(MaxLen)] of Char;
begin
FD_ZERO(Rfds);
FD_SET(FSock, Rfds);
Found := select(FSock, @Rfds, nil, nil, @FTimeout);
if Found = 0 then
begin
Result := -1;
exit;
end
else
if Found = SOCKET_ERROR then
begin
Result := -1;
exit;
end;
TotalBytesToRead := 0;
if BytesExpected <> 0 then
begin
TotalBytesToRead := BytesExpected;
end
else
begin
if ioctlsocket(FSock, FIONREAD, TotalBytesToRead) = SOCKET_ERROR then
begin
Result := -1;
exit;
end;
if TotalBytesToRead = 0 then
begin
SocketDisconnect();
Result := 0;
exit;
end;
end;
TotalBytesRead := 0;
repeat
if TotalBytesToRead > MaxLen then
BytesToRead := MaxLen
else
BytesToRead := TotalBytesToRead;
ZeroMemory(@TempBuff[0], MaxLen);
BytesRead := recv(FSock, TempBuff, BytesToRead, 0);
if BytesRead = SOCKET_ERROR then
begin
SocketDisconnect();
Result := -1;
exit;
end
else
if BytesRead = 0 then
begin
SocketDisconnect();
Result := 0;
exit;
end
else
begin
if ABuffer.Size >= 2097152 then
begin
SocketDisconnect();
Result := -1;
exit;
end;
ABuffer.Append(@TempBuff[0], BytesRead);
TotalBytesRead := TotalBytesRead + BytesRead;
TotalBytesToRead := TotalBytesToRead - BytesRead;
end;
until TotalBytesToRead <= 0;
Result := TotalBytesRead;
end;
Это крутится в цикле, если происходит дисконнект - соединение восстанавливается. Функции коннекта и дисконнекта не привожу - они тут не при чем.
Вторичный поток копит данные в некоторый буфер, при появлении в буфере маркеров начала и конца блока данных указатель на блок пересылается в основной поток через SendMessage().
← →
Сергей М. © (2007-04-16 12:39) [16]А что делает осн.поток при получении блока ?
← →
DVM © (2007-04-16 12:40) [17]
> А что делает осн.поток при получении блока ?
На диск его записывает в предварительно открытый файл.
← →
Сергей М. © (2007-04-16 12:42) [18]А где же тогда клиент проявляет "активность" ?
Где и при каких условиях он что-то отправляет серверу ?
← →
DVM © (2007-04-16 12:50) [19]
> А где же тогда клиент проявляет "активность" ?
В том цикле, который крутится в доп потоке клиент делает HTTP - запрос после того как выделен блок данных, чтобы сервер слал следующий.
Тут вот такая старанная закономерность всплыла. Проблема проявляется только тогда, когда окно приложения расположено на втором мониторе, подключенном к второй видеокарте. Причем когда монитор выключен и появляется заставка.
Вот стечение этих факторов приводит к тому, что клиент перестает писать данные.
Короче, я ухожу - выключаю монитор второй - утром прихожу смотрю - после моего ухода писалось еще пару минут и дальше пусто.
← →
Сергей М. © (2007-04-16 12:58) [20]
> после того как выделен блок данных
Как же он будет "выделен", если select вернул отказ (что, как ты утверждаешь, есть следствие разрыва соединения по инициативе сервера) и при этом процедура ReadData немедленно завершается ?
Что делает вызывающий код по возврату из ReadData c результатом -1 ?
← →
DVM © (2007-04-16 13:14) [21]
> Как же он будет "выделен", если select вернул отказ (что,
> как ты утверждаешь, есть следствие разрыва соединения
> по инициативе сервера) и при этом процедура ReadData немедленно
> завершается ?
Если ReаdData вернет -1 то клиент отключает сокет, ждет пару секунд и пытается подключить сокет вновь, затем при удаче делает запрос, потом опять начинает читать ответ сервера если таковой есть.
Если ReadData возвращает 0 это означает, что сервер выдал все имеющиеся на данный момент у него данные - ищем там маркеры - если блок найден, высылаем его в основной поток, далее дисконнект с сервером и пошли заново - коннект, запрос, чтение.
Если ReadData возвращает > 0, продолжаем вызывать ReadData до тех пор пока в буфере не образуется целый блок, затем высылаем его в основной поток, после чего выкидываем целый блок из буфера а серверу посылаем запрос, чтобы слал следующий блок.
Код привести не могу, т.к. он длинный а к делу относится далеко не вся его чать.
С логикой приема проблем нет - все же прекрасно работает без заставки и проблема только при появлении оной.
← →
Alex Konshin © (2007-04-16 13:15) [22]Ну не используй ты окна.
Используй Winsock2 возможности работать с сокетом без окна.
← →
DVM © (2007-04-16 13:20) [23]
> Ну не используй ты окна.
Да я с сокетом без окон и работаю. Это уже готовый результат пересылается в окно, а там уже и записывается. Окно одно - в основном потоке.
← →
Сергей М. © (2007-04-16 13:33) [24]
> ждет пару секунд
Надо понимать, не без помощи TTimer ?
Пойми, все идет к проблеме с оконными сообщениями.
← →
DVM © (2007-04-16 13:39) [25]
> Надо понимать, не без помощи TTimer ?
Без помощи таймера он ждет, конечно же. Он просто sleep(2000) делает. Хочу повторить Sleep в потоке принимающем даннные именно.
Вторичный поток не знает и не использует НИЧЕГО короме хэндла основного окна из основного потока. Ничего относящегося к VCL (кроме TThread самого).
← →
Сергей М. © (2007-04-16 13:45) [26]Результаты вызовов connect(), send() ты протоколируешь ?
Что показывает протокол ?
← →
isasa © (2007-04-16 13:51) [27]Тут эта, тупой вопрос. А "без заставки" все работает?
← →
DVM © (2007-04-16 13:56) [28]
> А "без заставки" все работает?
Да, конечно же.
> Сергей М. © (16.04.07 13:45) [26]
> Результаты вызовов connect(), send() ты протоколируешь ?
>
Я кажется нашел проблему. Почему то пересоздается окно при всех этих манипуляциях с заставками/мониторами. Как раз то окно, которому поток должен слать сообщение. Сообщения уходят в никуда.
← →
Сергей М. © (2007-04-16 13:58) [29]
> Как раз то окно, которому поток должен слать сообщение.
> Сообщения уходят в никуда
ну даже если и в никуда - какое отношение это имеет к активности клиента ?
Ведь ты же утверждаешь, что осн.поток НЕ имеет никакого отношения к транспорту ?
← →
DVM © (2007-04-16 14:05) [30]
> ну даже если и в никуда - какое отношение это имеет к активности
> клиента ?
> Ведь ты же утверждаешь, что осн.поток НЕ имеет никакого
> отношения к транспорту ?
Ну сказать, что совсем не имеет нельзя. Не совсем я правильно описал ситуацию. Связь эта есть - и она как раз через Result в SendMessage(). Поток получает неверный результ и крутится вхолостую - не делает запросы к серверу (так в коде описано). Вот и грабли.
Всем спасибо. Сделал уведомление потока об изменении хэндла - вроде работает.
← →
isasa © (2007-04-16 14:18) [31]DVM © (16.04.07 13:56) [28]
Да, конечно же.
Я к чему спросил.
Как-то столкнулся с неприятным моментом. Обычный SQL клиент(Delphi+ADO) и длительное задание(оставляли на ночь), протокол выполнения писалсяв файл(сколько сделано, сколько осталось...). Так вот, во время работы при старте скрин сейвера или заставки обмен замирал(хоч на TCP/IP, хоч на pipes). С тех пор, я заставки и сейверы при такой работе вырубаю. :)
← →
Сергей М. © (2007-04-16 14:28) [32]
> Почему то пересоздается окно
Хм..
Вот смотрю я исходники юнита forms в D7 VCL и чешу репу насчет "почемуты" - метод TWinControl.RecreateWnd "самопроизвольно" нигде не вызывается - всюду, где наблюдается его вызов, это связано с явным программным изменением тех или иных публичных свойтв объекта-наследника этого класса.
← →
DVM © (2007-04-16 14:40) [33]
> Сергей М. © (16.04.07 14:28) [32]
> Хм..
Код основного потока я полностью внимательно не глядел (не я его писал, я переделываю) - может там и есть какая либо причина приводящая к пересозданию окна (она там конечно должна быть). Поищу чуть позже.
← →
Сергей М. © (2007-04-16 14:49) [34]
> DVM © (16.04.07 14:40) [33]
Но в таком случае каким образом ты "ловишь" момент пересоздания целевого окна ? Каким-то событием руководствуешься или где ?
← →
DVM © (2007-04-16 15:06) [35]
> Сергей М. © (16.04.07 14:49) [34]
procedure TMySuperPuperWindow.CreateHandle;
begin
inherited;
if FThread <> nil then FThread.Handle := self.Handle;
end;
← →
DVM © (2007-04-16 15:09) [36]Само собой
protected
procedure CreateHandle; override;
← →
Сергей М. © (2007-04-16 15:10) [37]
> DVM © (16.04.07 15:06) [35]
Врешь)
CreateHandle - статический метод)
> FThread.Handle
Если FThread есть TThread, то опять врешь - его св-во Handle не имеет ничего общего с оконными хэндлами.
← →
Сергей М. © (2007-04-16 15:11) [38]TMySuperPuperWindow - чей наследник ?
← →
DVM © (2007-04-16 15:18) [39]
> Сергей М. © (16.04.07 15:10) [37]
Я не знаю, чего вы добиваетесь, но извольте:
> Врешь)
>
> CreateHandle - статический метод)
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
protected
procedure CreateHandle; override;
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.CreateHandle;
begin
inherited;
Windows.Beep(500,50);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
end;
end.
Даже на примере формы прекрасно бибикает!
> TMySuperPuperWindow - чей наследник ?
TCustomControl
> > FThread.Handle
>
>
> Если FThread есть TThread, то опять врешь - его св-во Handle
> не имеет ничего общего с оконными хэндлами.
Описка это. Там надо FThread.FHandle := self.Handle;
И, придвидя следующие придирки, скажу сразу обращение к FThread.FHandle что на чтение, что на запись завернуто в критические секции в самом FThread.
← →
DVM © (2007-04-16 15:22) [40]
> Если FThread есть TThread, то опять врешь - его св-во Handle
> не имеет ничего общего с оконными хэндлами.
У объекта TThread свойства Handle нет!
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2007.05.13;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.042 c