Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2008.10.19;
Скачать: [xml.tar.bz2];

Вниз

Для опытного глаза   Найти похожие ветки 

 
Dennis I. Komarov ©   (2007-10-16 10:11) [0]

код модуля потока предназначенного для транспорта пакетов с диска в и-нет(FTP)
Еще неизвестно как будет хранится база клиентов и не ведуться логи

Просьба посмотреть данный код на корректность, в смысле поведения при нестабильном конекте (ну и вообще :) )


unit u_send;

interface

uses
 Classes, Windows, SysUtils, StrUtils, DateUtils,
 IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;

type
 TThreadSend = class(TThread)
 private
   { Private declarations }
 protected
   procedure Execute; override;
 end;

var
 FTP: TIdFTP;

implementation

uses
 Main;

{ Important: Methods and properties of objects in visual components can only be
 used in a method called using Synchronize, for example,

     Synchronize(UpdateCaption);

 and UpdateCaption could look like,

   procedure TThreadSend.UpdateCaption;
   begin
     Form1.Caption := "Updated in a thread";
   end; }

{ TThreadSend }

procedure TThreadSend.Execute;

var
 SearchRec: TSearchRec;
 FindResult: Integer;

 ClientCode: string;
 FTPLogin: string;

 HomeDir: string;

begin
 { Place thread code here }

 FTP:=TIdFTP.Create(nil);
 try
   FTP.Host:="**.**.**.***";
   FTP.Username:="********";
   FTP.Password:="********";
   FTP.Passive:=true;
   while not Terminated do begin
     {для каждого клиента делать } begin
       FindResult := FindFirst(BCDir + "\MAILBOX\" + ClientCode + "\POSTIN\*.*", faAnyFile, SearchRec);
       while FindResult = 0 do  begin
         with SearchRec do
           begin
             if (Name <> ".") and (Name <> "..") then
               if not (Attr and faDirectory <> 0)
                 then begin
                   if not(FTP.Connected) then
                     try
                       FTP.Connect;
                       HomeDir:=FTP.RetrieveCurrentDir;
                     except
                       FTP.Disconnect;
                     end;
                   if FTP.Connected then
                     try
                       FTP.ChangeDir(HomeDir + "/" + FTPLogin + "/MBOX/RT");
                       FTP.Put(BCDir + "\MAILBOX\" + ClientCode + "\POSTIN\" + Name, Name);
                       if FTP.Size(Name) = Size then begin
                         FTP.Rename(Name, "../R/" + Name);
                         DeleteFile(BCDir + "\MAILBOX\" + ClientCode + "\POSTIN\" + Name);
                       end;
                     except
                       FTP.Disconnect;
                     end;
                 end;
             FindResult:= FindNext(SearchRec);
           end;
       end;
       FindClose(SearchRec);
     end;
     FTP.Disconnect;
     Sleep(15000);
   end;
 finally
   FTP.Disconnect;
   FTP.Free;
 end;
end;
end.


 
Сергей М. ©   (2007-10-16 13:59) [1]


> ну и вообще


Sleep(15000) - это зачем ?


 
Dennis I. Komarov ©   (2007-10-16 15:35) [2]

> [1] Сергей М. ©   (16.10.07 13:59)

Что бы FTP не поплохело :)


 
Сергей М. ©   (2007-10-16 15:44) [3]


> Dennis I. Komarov ©   (16.10.07 15:35) [2]


Каким образом протоколу может "поплохеть" или "похорошеть" от твоего sleep"а или его отсутствия ?


 
Dennis I. Komarov ©   (2007-10-16 18:00) [4]

Разумеется я про FTP-сервер, хотя если файлов для отправки нет - связываться он не будет. Просто нет необходимости бродить по диску все время. Побродил - на отдых (дай другим поработать), нашел - отправил.

А что, в этом есть что-то критичное?


 
Slym ©   (2007-10-17 09:16) [5]

var FTP: TIdFTP;
засунь в тело потока


 
Сергей М. ©   (2007-10-17 09:26) [6]


> нет необходимости бродить по диску все время. Побродил -
>  на отдых (дай другим поработать), нашел - отправил


Дык на то есть асинхроннаая ReadDirectoryChangesW)
При ее использовании нет необходимости "бродить по диску" вообще - система сама известит тебя о произошедших измениях.


> в этом есть что-то критичное?


В принципе нет, но и резона тоже нет. И уж тем более непонятно, как это сказывается на работе FTP-сервера, так что без этой задержки серверу "заплохеет".

Гораздо более критично [5].


 
Dennis I. Komarov ©   (2007-10-17 10:02) [7]

> Гораздо более критично [5].

Это да, согласен.

> ReadDirectoryChangesW

Не слышал про такую :) Пойду гляну, что за зверь.


 
Сергей М. ©   (2007-10-17 10:05) [8]


> Пойду гляну, что за зверь


Оч даже симпатичный, ласковый и некапризный)


 
Dennis I. Komarov ©   (2007-10-17 14:11) [9]

> [8] Сергей М. ©   (17.10.07 10:05)

Я так понял, что если программа не запущена, то все изменения за это время пройдут мимо. Т.е. сперва все равно надо "побродить по диску"?


 
Сергей М. ©   (2007-10-17 15:04) [10]


> Dennis I. Komarov ©   (17.10.07 14:11) [9]


Угу.


 
Dennis I. Komarov ©   (2007-10-19 13:40) [11]

Вот и вернулся я :)


> Сергей М. ©

В результате, наверное должно получиться что-то подобное:


unit u_send;

interface

uses
 Classes, Windows, SysUtils, StrUtils, DateUtils,
 IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;

type
 TThreadSend = class(TThread)
 private
   { Private declarations }
 protected
   procedure Execute; override;

 end;

var

implementation

uses
 Main;

{ TThreadSend }
type
 PFileNotifyInformation = ^TFileNotifyInformation;
 TFileNotifyInformation = packed record
   NextEntryOffset: DWORD;
   Action: DWORD;
   FileNameLength:DWORD;
   FileName: WideChar;
 end;

procedure TThreadSend.Execute;

var
 FTP: TIdFTP;

 SearchRec: TSearchRec;
 FindResult: Integer;

 ClientCode: string;
 FTPLogin: string;

 HomeDir: string;
 hDir: THandle;

 lpBuf: Pointer;
 lpOverlapped: POverlapped;

begin
 { Place thread code here }
 FreeOnTerminate:=false;
 hDir := CreateFile ( "c:\test", GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
 if hDir <> INVALID_HANDLE_VALUE then begin
   GetMem(lpBuf, 64*1204);
   GetMem(lpOverlapped, SizeOf(lpOverlapped));
   try
     ZeroMemory(lpBuf, SizeOf(lpBuf));
     ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
   finally
     FreeMem(lpBuf); FreeMem(lpOverlapped);
   end;

 end;
end;
end.



При выполнении такого кода, я так понимаю будет поспавлен запрос в очередь. Как только что-то в директории(дереве) изменится мы должны "получить" событие, которое надо как-то связать с помощью GetOverlappedResult в сруктуре _Overlapped.hEvent с дискриптором события?
Вобщем не совсем понятно, как получить извещение от системы.


 
Сергей М. ©   (2007-10-19 13:50) [12]


> событие, которое надо как-то связать с помощью GetOverlappedResult
> в сруктуре _Overlapped.hEvent с дискриптором события


Прежде чем обращаться к дескриптору события нужно создать этот объект. А ты его не создал.


 
Dennis I. Komarov ©   (2007-10-19 14:56) [13]

> Прежде чем обращаться к дескриптору события нужно создать
> этот объект

Разумеется, но я к нему еще и не обращался :)

Просто выложил код чтоб проверить, правильно ли я понимаю свои действия


 
Сергей М. ©   (2007-10-19 15:05) [14]


> я к нему еще и не обращался


Как это не обращался ?

Ты передал параметром overladded-структуру, в которой поле hEvent = 0, вместо того чтобы содержать хэндл ивент-объекта.

Как же система уведомит тебя о наступившем событии, если ты не указал посредством какого объекта тебя уведомлять ?


 
Dennis I. Komarov ©   (2007-10-19 16:24) [15]

А если передать указатель @AnyProc

procedure AnyProc;
begin
end;


 
Dennis I. Komarov ©   (2007-10-19 16:28) [16]

> [15] Dennis I. Komarov ©   (19.10.07 16:24)

Бредю :) Адрес памяти <> хэндлу системы


 
Сергей М. ©   (2007-10-19 16:33) [17]


> если передать указатель @AnyProc


Имеешь ввиду параметр lpCompletionRoutine ?

Да, можно и так. Но прототип этой ф-ции должен соответствовать прототипу FileIOCompletionRoutine (см. справку)


 
Dennis I. Komarov ©   (2007-10-23 16:00) [18]

> [14] Сергей М. ©   (19.10.07 15:05)

Предположим создал некую:

type
 OnDirectoryChange = procedure(Sender: TObject);  // Зачем нужен sender сам еще не знаю, но пускай бубет :)
...

procwdure OnDirectoryChange((Sender: TObject);
begin
// делать что-то при обнаружении нового файла, а точнее шмальнуть его...

end;


А как узнать хандл процедуры?

Мыслю в верном направлении?


 
Сергей М. ©   (2007-10-23 16:16) [19]


> Dennis I. Komarov ©   (23.10.07 16:00) [18]


> Мыслю в верном направлении?


Нет.

Ты про прототип FileIOCompletionRoutine вник ?


 
Anatoly Podgoretsky ©   (2007-10-23 16:17) [20]

> Dennis I. Komarov  (23.10.2007 16:00:18)  [18]

Какой еще хендл у процедуры?


 
Dennis I. Komarov ©   (2007-10-23 16:33) [21]

> [19] Сергей М. ©   (23.10.07 16:16)

Нет, я отвернулся в сторону GetOverLappedResult.

> Ты передал параметром overladded-структуру, в которой поле
> hEvent = 0, вместо того чтобы содержать хэндл ивент-объекта.

или в данном случае это будет @OnDirectoryChange?
Или ивент-объект не есть процедура?


 
Сергей М. ©   (2007-10-23 16:53) [22]


> ивент-объект не есть процедура?
>


Конечно не процедура.

ивент-объект создается вызовом CreateEvent()


 
Dennis I. Komarov ©   (2007-10-23 17:14) [23]


uses
Main;

{ TThreadSend }
type
PFileNotifyInformation = ^TFileNotifyInformation;
TFileNotifyInformation = packed record
  NextEntryOffset: DWORD;
  Action: DWORD;
  FileNameLength:DWORD;
  FileName: WideChar;
end;

procedure TThreadSend.Execute;

var
FTP: TIdFTP;

SearchRec: TSearchRec;
FindResult: Integer;

ClientCode: string;
FTPLogin: string;

HomeDir: string;
hDir: THandle;

lpBuf: Pointer;
lpOverlapped: POverlapped;
hOnDirChange: THandle;

begin
{ Place thread code here }
FreeOnTerminate:=false;
hOnDirChange:=CreateEvent(nil, false, true, PChar("OnChangeDirectory");
hDir := CreateFile ( "c:\test", GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
if hDir <> INVALID_HANDLE_VALUE then begin
  GetMem(lpBuf, 64*1204);
  GetMem(lpOverlapped, SizeOf(lpOverlapped));
  try
    ZeroMemory(lpBuf, SizeOf(lpBuf));
    lpOverlapped^.hEvent:=hOnDirChange;
    ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
  finally
    FreeMem(lpBuf); FreeMem(lpOverlapped);

  end;

end;
end;
end.


Похоже? И как отлавливать теперь это событие?


 
Сергей М. ©   (2007-10-24 09:21) [24]


> GetMem(lpOverlapped, SizeOf(lpOverlapped));


SizeOf(lpOverlapped) всегда равен 4, потому что это указатель.
Либо разыменовывай его для взятия размера либо объяви переменную TOverlapped, тогда и GetMem не потребуется.


> ZeroMemory(lpBuf, SizeOf(lpBuf));


Здесь та же самая грубая ошибка.


> как отлавливать теперь это событие?


Любой удобной функцией ожидания - WaitForSingleObject, MsgWaitForMultipleObjects и иже с ними.


 
Dennis I. Komarov ©   (2007-10-24 11:39) [25]


> > GetMem(lpOverlapped, SizeOf(lpOverlapped));
> > ZeroMemory(lpBuf, SizeOf(lpBuf));

Ой мама, это как это я??? Это я не специально :)


 
Dennis I. Komarov ©   (2007-10-24 16:57) [26]


unit u_send;

interface

uses
 Classes, Windows, SysUtils, StrUtils, DateUtils,
 IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdFTP, IniFiles;

type
 OnDirectoryChange = procedure(Sender: TObject);

 TThreadSend = class(TThread)
 private
   { Private declarations }

 protected
   procedure Execute; override;

 end;

var
 TCP: TIdTCPClient;
implementation

uses
 Main;
{ TThreadSend }
type
 PFileNotifyInformation = ^TFileNotifyInformation;
 TFileNotifyInformation = packed record
   NextEntryOffset: DWORD;
   Action: DWORD;
   FileNameLength:DWORD;
   FileName: WideChar;
 end;

procedure TThreadSend.Execute;

var
 hDir: THandle;
 hDirChangeEvent: THandle;

 lpBuf: Pointer;
 lpOverlapped: POverlapped;
begin
 { Place thread code here }
 FreeOnTerminate:=false;
 hDirChangeEvent:=CreateEvent(nil, false, true, PChar("OnChangeDirecory"));
 hDir := CreateFile ( "c:\test", GENERIC_READ, FILE_SHARE_READ, nil,
         OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS or FILE_FLAG_OVERLAPPED, 0);
 if hDir <> INVALID_HANDLE_VALUE then begin
   GetMem(lpBuf, 64*1024);
   GetMem(lpOverlapped, SizeOf(lpOverlapped^));
   try
     ZeroMemory(lpBuf, 64*1024);
     lpOverlapped^.hEvent:=hDirChangeEvent;
     ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
     while not Terminated do begin
       if WaitForSingleObject(hDirChangeEvent, 5000) = WAIT_OBJECT_0 then begin
         //Сюда должны попасть если в директории есть изменения
         //С помощью GetOverLappedResult
         //Если при чтении из lpBuf узнаем, что появился новый файл, тогда отправляем его споследствиями
         // Тут наверное надо обнулить lpBuf
         ReadDirectoryChangesW(hDir, lpBuf, SizeOf(lpBuf), true, FILE_NOTIFY_CHANGE_FILE_NAME, nil, lpOverlapped, nil);
       end;
     end;
   finally
     FreeMem(lpBuf); FreeMem(lpOverlapped);
   end;
 end;
end;
end.


??? :)


 
Сергей М. ©   (2007-10-24 17:10) [27]


> //Сюда должны попасть если в директории есть изменения


Да.


> //С помощью GetOverLappedResult
>          //Если при чтении из lpBuf узнаем, что появился
> новый файл, тогда отправляем его споследствиями


Да, но при условии что ф-ция вернула True


> // Тут наверное надо обнулить lpBuf


Нафига ?

И вообще заведи себе привычку вызывать WinAPI-функции как функции - возвращаемые ими результаты следует анализировать, ибо от них напрямую зависит дальнейшее правильное ветвление алгоритма.


> WaitForSingleObject(hDirChangeEvent, 5000)


Тебя не смущает, что в течение этих 5 сек. таймаута ожидания сигнала ивента твой поток не будет реагировать на флаг Terminated ?


 
Сергей М. ©   (2007-10-24 17:18) [28]


> FreeOnTerminate:=false;


Это лишнее.


> GetMem(lpOverlapped, SizeOf(lpOverlapped^));


Почему бы не сделать переменную Overlapped: TOverlapped локальной или полем класса ? Она ж крохотная, есть ли резон динамически распределять под нее память ?


> CreateEvent(nil, false, true, PChar("OnChangeDirecory"));


Почему true ? Он же у тебя сразу и просигналит, в то время как никаких изменений еще и в помине не было ...

Да и имя ивента не обязательно.


 
Dennis I. Komarov ©   (2007-10-25 10:21) [29]

> И вообще заведи себе привычку вызывать WinAPI-функции как
> функции - возвращаемые ими результаты следует анализировать,
> ибо от них напрямую зависит дальнейшее правильное ветвление
> алгоритма.

Угу. Это же пока черновик :) Ну мне сейчас хочется разобраться в логике ассинхронного вызова.


> > //Сюда должны попасть если в директории есть изменения
>
>
> Да.

Логично предположить, что при этом запрос в очереди уже отсутствует!?


> > WaitForSingleObject(hDirChangeEvent, 5000)
>
>
> Тебя не смущает, что в течение этих 5 сек. таймаута ожидания
> сигнала ивента твой поток не будет реагировать на флаг Terminated
> ?

Ну вообще не смущает. Если при остановки вся это бодяга остановится через пять сек. меня это не очень расстроит, хотя сделую 1000 :) Уговорил.

> > GetMem(lpOverlapped, SizeOf(lpOverlapped^));
>
>
> Почему бы не сделать переменную Overlapped: TOverlapped
> локальной или полем класса ? Она ж крохотная, есть ли резон
> динамически распределять под нее память ?

А разница?

> > CreateEvent(nil, false, true, PChar("OnChangeDirecory")
> );
>
>
> Почему true ? Он же у тебя сразу и просигналит, в то время
> как никаких изменений еще и в помине не было ...

Да, тут не правильно перевел "F1" :)

> Да и имя ивента не обязательно.

Ну пускай будет :)


 
Сергей М. ©   (2007-10-25 10:50) [30]


> Логично предположить, что при этом запрос в очереди уже
> отсутствует!?


Конечно.
Его результаты выбраны из очереди в указанный тобой буфер.


> сделую 1000 :) Уговорил


Да я тебя не уговаривал)
Просто есть гораздо более изящные решения для преодоления этой "проблемы")


 
Dennis I. Komarov ©   (2007-10-25 11:15) [31]

> есть гораздо более изящные решения

Пример? :)


 
Сергей М. ©   (2007-10-25 12:55) [32]

WaitFoeMultipleObjects, MsgWaitFoeMultipleObjects


 
Dennis I. Komarov ©   (2007-10-25 13:29) [33]

> [32] Сергей М. ©   (25.10.07 12:55)

А в чем принципиальная разница? Чем оно "изящней"?


 
Сергей М. ©   (2007-10-25 15:42) [34]

Тем что поток приобретает способность немедленно реагировать не только на твой overlapped-ивент, но и на другие ивенты и/или сообщения.


 
Dennis I. Komarov ©   (2007-10-25 16:48) [35]

Я думал изящность имено в решении, а не в возможностях

Есть приложение (возможно служба) задача которой транспортировка файлов с диска (не факт что локального) в сеть (FTP-сервер), и аналогично обратное. За каждое из действий отвечает свой поток. Ранее он (который отправлял) просто сканил папки на отправку (FindFirst/Next, ну сам видел). Более на него никаких функций не накладывается (разве что лог ). Другую смысловую нагрузку он не несет. Реакция на Terminated в течении секунды - это даже более чем :) .

Непонятна такая вешь: Мы посавили запрос в очередь. По некоему событию, мы получаем факт, что этот запрос обработался и в указанном месте появились изменения. Данные об изменениях храняться по адресу lpBuf. Далее мы отправляем аналогичный запрос в очередь.
1. На черта нам тогда функция GetOverlappedResult и
2. В то время, пока мы обрабатываем ин-цию об изменениех, происходящие изменения не фиксируются?


 
Сергей М. ©   (2007-10-26 08:08) [36]


> 1. На черта нам тогда функция GetOverlappedResult


Мало ли что могло произойти во время исполнения запроса !
Ф-ция как раз и покажет, успешно ли выполнен запрос.
А сигнал ивента лишь фиксирует факт завершения (успешного или неуспешного) асинхронной операции.


> пока мы обрабатываем ин-цию об изменениех, происходящие
> изменения не фиксируются?


Нет. Поэтому следует как можно быстрей после сигнала ивента принять решение о постановке очередного запроса и лишь потом разбирать результаты текущего выполненного.


 
Dennis I. Komarov ©   (2007-10-26 09:57) [37]

> Нет. Поэтому следует как можно быстрей после сигнала ивента
> принять решение о постановке очередного запроса и лишь потом
> разбирать результаты текущего выполненного.

Гм... Но для этого все равно понадобится какое то время, т.е.
Получили сигнал события, далее по идее запроса в очереди нет, следует отправить его еще раз, отправлять с тем же указателем на буфер низя - можем потерять его, следовательно, предварительно надо сохранить данные, это потребует некоторого времени, за которое могут произойти изменения, начинаю подумывать о том, что "сканить" диск всетаки надежнее


> Мало ли что могло произойти во время исполнения запроса
> !
> Ф-ция как раз и покажет, успешно ли выполнен запрос.
> А сигнал ивента лишь фиксирует факт завершения (успешного
> или неуспешного) асинхронной операции.


hFile - чего она сюда хочет?


 
Сергей М. ©   (2007-10-26 11:23) [38]


> чего она сюда хочет?


hDir твой она хочет.


 
Сергей М. ©   (2007-10-26 11:44) [39]


> "сканить" диск всетаки надежнее


С чего бы ?

Explorer, заметь, использует именно ReadDirectoryChangesW


 
Dennis I. Komarov ©   (2007-10-26 12:26) [40]

> [39] Сергей М. ©   (26.10.07 11:44)

Но ведь не асинхронный.



Страницы: 1 2 вся ветка

Форум: "Сети";
Текущий архив: 2008.10.19;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.58 MB
Время: 0.007 c
2-1221465868
Ruzzz
2008-09-15 12:04
2008.10.19
Какая версия Delphi официально поддерживает unicode-прилождения?


2-1221045757
Нов_и_чок
2008-09-10 15:22
2008.10.19
Системные иконки Shell32.dll


2-1221057756
deras
2008-09-10 18:42
2008.10.19
Работа с датой


15-1220006311
Альф
2008-08-29 14:38
2008.10.19
Ищу простой класс для POP3 и IMAP4 с функциями:


3-1208278127
Вопрос
2008-04-15 20:48
2008.10.19
как найти 10 "последних записей" в sql ?





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский