Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.05.13;
Скачать: CL | DM;

Вниз

Вопрос по энергосбережению и экранной заставке. Проблема.   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.58 MB
Время: 0.072 c
2-1177416513
Ксандр
2007-04-24 16:08
2007.05.13
SendMessage...


2-1177339902
Саня Сафронов
2007-04-23 18:51
2007.05.13
Помогите, пожалуйста, составить прогу!


15-1176037360
Nic (ro)
2007-04-08 17:02
2007.05.13
Siemens A50


2-1176895225
Ксандр
2007-04-18 15:20
2007.05.13
хеш функция


2-1177078983
roman_ln
2007-04-20 18:23
2007.05.13
TDBNavigator как обработать событие кнопки