Текущий архив: 2008.10.19;
Скачать: CL | DM;
ВнизДля опытного глаза Найти похожие ветки
← →
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;
Скачать: CL | DM;
Память: 0.58 MB
Время: 0.006 c