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

Вниз

Как грамотно организовать копирование файлов по локалке. (+)   Найти похожие ветки 

 
EarlVadim ©   (2006-01-18 10:42) [0]

Есть необходимость периодически опрашивать удалённые хосты (с доступом естессно) на наличие в сети, и в положительном случае, копировать с них определённый файл.

Сейчас тупо используеься COPYFILE(SFN,TFN); Проблема в том, что процесс копирования файла "примораживает" программу, а если хост недоступен, то это уже на 5-10 секунд "заморозка". Ни свернуть, ни закрыть, ничего.  Файл небольшой - до 100Кб.

Как это НАДО делать, чтобы процесс опроса-копирования действительно был ФОНОВЫМ?


 
EarlVadim ©   (2006-01-18 10:45) [1]

Да, чуть не забыл,  Сеть- MS на TCP/IP


 
Fay ©   (2006-01-18 11:37) [2]

2 EarlVadim ©   (18.01.06 10:42)
Вытащи в отдельный поток.


 
EarlVadim ©   (2006-01-18 11:39) [3]

Не сталкивался.
Если не в лом, как делать?


 
Fay ©   (2006-01-18 11:45) [4]

2 EarlVadim ©   (18.01.06 11:39) [3]
CreateThread | свой наследник TThread


 
EarlVadim ©   (2006-01-18 12:41) [5]

2 Fay ©  (18.01.06 11:45) [4]

Я тут в сети нашёл пример создания приложения с двумя потоками.
http://rusasdatabase.narod.ru/threads.html

Все работает, все ОК.  Но вот вопрос, как прикрутить это все себе.
Объясните принцип.  Вся программа должна быть одним потоком, а CopyFile - вторым,  Или просто создать в программе один поток с CopyFile?


 
Digitman ©   (2006-01-18 17:32) [6]

реализуй код доп.потока, который собственно и будет заниматься копированием файла.

ссылку на местоположение файла передавай параметром при конструировании потока


 
EarlVadim ©   (2006-01-19 09:37) [7]

2 Digitman ©   (18.01.06 17:32) [6]

Ну с принципом я в общем-то разобрался.
Простая прога с потоком - работает.
Вставляю теже самые компоненты, процедуры, классы в свою программу,  поток не работает. (Хотя в теле потока для начала все предельно просто)


unit MyThreadU;

interface

uses
 Classes, Windows, SysUtils, Variants;

type
 MyThread = class(TThread)
 private
   { Private declarations }
 protected
   procedure Execute; override;
 public
   i1  : integer;
   s1 : string;
 end;

implementation

procedure MyThread.Execute;
begin

     s1:= IntToStr(i1);

end;

end


Соответственно в главной проге

Procedure TMainForm.ReadData(Sender: TObject);
Var iz : integer;
begin
   Thread := MyThread.Create(true);
   Thread.Priority := tpLowest;
   Thread.FreeOnTerminate:= false;  
   For iz:= 0 to 9 do BEGIN
      Thread.i1:= iz;
      Thread.Resume;
      Labels[iz].Caption:= Thread.s1;
   END;
   Thread.Destroy;
end;


Чтоже у меня не правильно? Пробовал разные варианты. И Create/Destroy ставил в тело цикла. И Create(false) писал - ничего.  "s1" всегда = "";


 
Digitman ©   (2006-01-19 09:59) [8]

MyThread = class(TThread)
private
  FParameter: Integer;
  FResult: String;  
protected
  procedure Execute; override;
public
  constructor Create(Parameter: Integer);
  property MyResult: String read FResult;
end;

..

constructor MyThread.Create(Parameter: Integer);
begin
 FParameter: Integer;
 inherited Create(False);
end;

procedure MyThread.Execute;
begin
  FResult := IntToStr(FParameter);
end;

...

Procedure TMainForm.ReadData(Sender: TObject);
Var iz : integer;
begin
  For iz:= 0 to 9 do BEGIN
   Thread := MyThread.Create(iz);
   Thread.WaitFor;
   Labels[iz].Caption:= Thread.ExecResult;
   Thread.Destroy;
  END;
end;


 
EarlVadim ©   (2006-01-19 10:04) [9]

Digitman ©   (19.01.06 09:59) [8]

Спасибо...  Ведь как все просто, но сам не допрёшь...


 
EarlVadim ©   (2006-01-20 10:15) [10]

Digitman ©   (19.01.06 09:59) [8]

Этсамое.... Ну прикрутил я всё в свою прогу, все работает, но эффекта положительного нет. Все дело в Thread.WaitFor;  
Обясняю:  в теле MainForm организован цикл  "по всем хостам читать файл и данные файла хитрым образом обрабатывать". Чтение файлов я воткнул в поток, а вот обработка у меня в MainForm. Так вот, пока файл по сети читаясь тупит, программа, следуя WaitFor тоже приморожена. Но если WaitFor убрать, то естессно нифига неработает.  Какой для этого выход?
Мне видится так, что я должен в поток переместить всю процедуру (и чтения файлов и их обработку и вывод результатов в окно программы).

Или есть другие способы?


 
Digitman ©   (2006-01-20 13:45) [11]


> Или есть другие способы?


Конечно же есть.

WaitFor был простейшим решением для оригинального примера в [7].

В изложенном же в [10] случае можно поступить, например, так:

MyThread = class(TThread)
private
 FParameter: String;
 FResult: String;  
protected
 procedure Execute; override;
public
 constructor Create(DownloadURL: String; Suspended: Boolean);
 property DownloadedFileName: String read FResult;
end;

..

constructor MyThread.Create(DownloadURL: String; Suspended: Boolean);
begin
FParameter := DownloadURL;
inherited Create(Suspended);
end;

procedure MyThread.Execute;
begin
try
.. попытка закачки файла по локатору в FParameter ..
 FResult := ... полный путь к закачанному файлу .. //закачка успешна
except
  .. закачка неуспешна ..
end;
end;

...

Procedure TMainForm.ProcessFile(Sender: TObject);
begin
  with TMyThread(Sender) do begin
    if DownloadedFileName <> "" then //закачка успешна
      Labels[..].Caption:= DownloadedFileName;// эмуляция "обработки файла" для примера
  end;
end;
 

  Thread := MyThread.Create(... конкретный URL файла .., True);
  Thread.FreeOnTerminate := True;
  Thread.OnTerminate := ProcessFile; //назначенный обработчик события OnTerminate будет вызван в осн.потоке процесса сразу после завершения метода MyThread.Execute;
//   Labels[iz].Caption:= Thread.ExecResult;
//   Thread.Destroy;


 
EarlVadim ©   (2006-01-24 17:12) [12]

Digitman ©   (20.01.06 13:45) [11]

Нифига не работает такой вариант.
ProcessFile - не выполняется.


 
Digitman ©   (2006-01-24 17:26) [13]


> EarlVadim ©   (24.01.06 17:12) [12]


отладчик тебе в руки


 
EarlVadim ©   (2006-01-24 17:47) [14]

Digitman ©   (24.01.06 17:26) [13]

По шагам прошёл,  не передаётся выполнение туда и всё тут.
В общем, в печали я.


 
EarlVadim ©   (2006-01-24 18:23) [15]

Скажу больше,  без Thread.WaitFor; Execute вообще не факт что получит управление.  У меня в 4-х вариантах пробы потока, так вот работают потоки в 2-х, а в 2-х других - НЕТ.  Все вызовы идентичны, голова уже пухнет...


 
Digitman ©   (2006-01-25 09:38) [16]


> без Thread.WaitFor; Execute вообще не факт что получит управление


получит, если поток не создан как suspended.
и это факт.

установи брейкпойнт

procedure MyThread.Execute;
begin //<- ЗДЕСЬ
..
end;

вызови

Thread := MyThread.Create(..., False);

и убедись в "факте".

Единственное что я упустил в [11] и что важно в том контексте :

//поток создается как suspended для того чтобы перед началом его выполнения можно было назначить нужные нам св-ва

Thread := MyThread.Create(... конкретный URL файла .., True);  

//поток должен разрушить себя сам после завершения выполнения
Thread.FreeOnTerminate := True;

//назначение обработчика события
 Thread.OnTerminate := ProcessFile; //назначенный обработчик события OnTerminate будет вызван в осн.потоке процесса сразу после завершения метода MyThread.Execute;

//и наконец "пробуждаем" поток !
 Thread.Resume;


 
EarlVadim ©   (2006-01-25 11:20) [17]

Thread.Resume; я пробовал и раньше.  Сейчас сделал все как написано.
Проставил два брейка.
Результат:

Ни на BEGIN  в Execute, ни на BEGIN в ProcessFile выполнение не останавливается, -> ход выполнения до них не добирается.
Может D7 глючит?  Хотя в другой версии той же проги у меня работает код без WaitFor.  Но та версия сама по себе меня не устраивает.

Придётся с нуля проект создавать, видимо.


 
Digitman ©   (2006-01-25 11:28) [18]


> Может D7 глючит?


"Это вряд ли .." (с) Ф.Сухов

Приводи полный код в последней своей редакции (неработающей)


 
EarlVadim ©   (2006-01-25 12:45) [19]


> Приводи полный код в последней своей редакции (неработающей)


:) Мне уже подсказали. Все дело в неверном месте вызова DESTROY;
Поток не устевает выполнится до EXECUTE когда основная программа вызывает DESTROY. Щас переписал код так, чтобы поток жил постоянно.
Просто пока параметром не пошлю TRUE - в теле EXECUTE выполняется пустой цикл. После выполнения EXECUTE флаг снова ставлю в FALSE и выполняю опять пустой цикл.
Вот про красоту решения спорить не готов. Нормально это или нет?

Но тебе отдельное спасибо за помощь в понимании основного принципа потоков и терпение к нам, "чайникам".


 
EarlVadim ©   (2006-01-25 12:53) [20]


> Digitman ©   (25.01.06 11:28) [18]


И кстати, вопрос о том, как быстро опросить заданные хосты, на предмет их наличия в сети в данный момент. Я сейчас использую:

For i:= 0 to Len-1 do begin
    st:= TStringList.Create;
    try
        If FileExists(PChar(CF[i])+"\unitinfo.txt") then begin  // в CF:array of string - хранятся пути в виде "\\host1\path1"
           st.LoadFromFile(PChar(CF[i])+"\unitinfo.txt");
           FOutPar[i]:= ST.Strings[4];  
// это вывод результата тестовый - просто возвращается 4-я строка файла.
// На самом деле будет работа с данными файла намного насыщеннее
        end else FOutPar[i]:= "";
    finally
        FReady[i]:= true;
//  Установка флага о том, что этот сервер прочитан, основная прога
//  Ориентируется на него и забирает FOutPar не дожидаясь остальных
        st.free;
    end;
end;

Есть советы для меня?


 
Digitman ©   (2006-01-25 13:14) [21]


> про красоту решения спорить не готов. Нормально это или
> нет?


Нет, не нормально.

Пустой цикл вида while Flag=False do; ощутимо отнимает процессорное время у других процессов и у других потоков того же процесса, не делая ничего полезного.

Да и нужно ли такое решение с циклами ?
Сомнительно.

Для начала следует одназначно определиться, будет ли созданный тобой поток использоваться однократно (т.е. будучи единожды созданный выполнит свою "миссию", после чего должен навсегда "умереть") либо многократно (т.е. будучи единожды созданный сможет выполнить множество "миссий", определенных различными передаваемыми ему параметрами)

Цикл в теле Execute (неважно какой, об этом - позже) напрашивается лишь при многократном использовании одного и того же объекта-потока.


 
EarlVadim ©   (2006-01-25 13:54) [22]


> либо многократно


Да. Через определяемые в настройках программы промежутки времени.
Приоритет потока Thread.Priority := tpLowest;
А цикл в потоке у меня выглядит так

While true do
    If FCheck then BEGIN
       FCheck:= false;
       For i:= 0 to Lens-1 do FReady[i]:= false;
       For i:= 0 to Lens-1 do begin
           st:= TStringList.Create;
           try
                If FileExists(PChar(CF[i])+"\unitinfo.txt") then begin
                     st.LoadFromFile(PChar(CF[i])+"\unitinfo.txt");
                     FOutPar[i]:= ST.Strings[4];
                end else FOutPar[i]:= "";
           finally
                FReady[i]:= true;            
           end;
                st.free;
       end;
 END;


 
Digitman ©   (2006-01-25 14:04) [23]

А должен выглядеть хотя бы так :

while not Terminated do begin
 FCommand := WaitCommand;
 if Terminated then Break;
 FResults := ProcessCommand(FCommand);
end;


 
Digitman ©   (2006-01-25 14:05) [24]

А должен выглядеть хотя бы так :

while not Terminated do begin
 FCommand := WaitCommand;
 if Terminated then Break;
 FResults := ProcessCommand(FCommand);
end;


 
EarlVadim ©   (2006-01-25 14:22) [25]

FCommand и FResults
Это переменные объявленные в private?
а ProcessCommand это процедура с моим кодом?
А что и откуда WaitCommand? какие значения может возвращать?


 
Digitman ©   (2006-01-25 15:15) [26]


> EarlVadim ©   (25.01.06 14:22) [25]
> FCommand и FResults
> Это переменные объявленные в private?


предположим - да...


> ProcessCommand это процедура с моим кодом?


опять же - например... т.е. - да ...


> что и откуда WaitCommand? какие значения может возвращать?


Это некий метод твоего класса TMyThread, который "приостанавливает" твой поток для ожидания "команд", ему адресованых ...

Он может возвращать некую команду, "посланную" потоку "извне" и которую данный поток должен исполнить.


 
EarlVadim ©   (2006-01-25 15:31) [27]

Теперь понятно.
Ну это симпатичный код.
Только вопрос с ожиданием - он открыт.
Хотя можно попробовать SUSPEND и RESUME передавать.

Но меня сейчас напрягает больше вопрос именно касающийся сетей, описанный мною выше.    (EarlVadim ©   (25.01.06 12:53) [20]).


 
Digitman ©   (2006-01-25 15:43) [28]


> меня сейчас напрягает больше вопрос именно касающийся сетей,
>  описанный мною выше


Дай свое определение термину "опрос хоста" ..


 
EarlVadim ©   (2006-01-25 16:35) [29]


> Дай свое определение термину "опрос хоста" ..


Наверное это PING.


 
Digitman ©   (2006-01-25 16:50) [30]

т.е. тебе необходимо осуществить Packet INternet Gopher ...


 
EarlVadim ©   (2006-01-25 18:01) [31]


> т.е. тебе необходимо осуществить Packet INternet Gopher
> ...


Не уверен.

Мне надо передать некой функции имя хоста ( напр. \\SERVER ) и в качестве результата получить от неё TRUE - если SERVER в локальной сети присутствует.  
Второй момент, есть ли способы ускорить первоначальное обращение к файлам на удалённом компьютере. Дело в том, что если программа читает эти файлы с некоторой периодичностью, напр. раз в минуту, то первое чтение занимает существенно бОльшее время чем последующие. Не знаю причин этого, и возможно на это нельзя повлиять. Поэтому и спрашиваю.


 
Digitman ©   (2006-01-26 08:35) [32]

Хосты в ЛВС имеют IP-адреса ?


 
EarlVadim ©   (2006-01-26 08:55) [33]


> Хосты в ЛВС имеют IP-адреса ?


Имеют.  Сеть MS на TCP/IP.


 
Digitman ©   (2006-01-26 09:30) [34]

Самый простой способ - использовать ICMP-клиента.

Например , компонент TIdICMPClient в составе Indy-пакета


 
EarlVadim ©   (2006-01-26 10:11) [35]

Делаю так:

IdIcmpClient1.ReceiveTimeout:= 10000;
IdIcmpClient1.Port:= 80;
IdIcmpClient1.Host:= Edit1.Text;
IdIcmpClient1.Ping("",0);
Label1.Caption:= IdIcmpClient1.ReplyStatus.FromIpAddress;

Некоторые хосты возвращают IP-адрес, а некоторые говорят
Error #11001 Host not found.  Задолго то окончания TimeOut;


 
Digitman ©   (2006-01-26 10:40) [36]

Это проблема с разрешением имени в IP-адрес - либо имя хоста неверно указано, либо на DNS-сервере отсутствует запись о хосте с указанным именем, либо проблемы в самой DNS-подсистеме


 
EarlVadim ©   (2006-01-26 10:46) [37]

Да действительно, не PINGуется этот хост.
М-да FileExists о таких мелочах не волнуется.



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

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

Наверх




Память: 0.56 MB
Время: 0.014 c
4-1141220323
ionn
2006-03-01 16:38
2006.05.21
Как отследить момент закрытия внешнего приложения?


2-1146907050
D@Nger
2006-05-06 13:17
2006.05.21
RxLib и Delphi 7


15-1146148622
oldman
2006-04-27 18:37
2006.05.21
Праздник. так уж праздник... :(


15-1145514246
Виталий Панасенко
2006-04-20 10:24
2006.05.21
Макс. длинна шнура между COM-портом и устройством


2-1146648778
KyRo
2006-05-03 13:32
2006.05.21
TClientSocket &amp;TServerSocket





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский