複数のFTPサーバーから並列でファイルをゲットするには

解決


紅閃光  URL  2008-09-18 19:40:16  No: 101083  IP: 192.*.*.*

環境:VB6+WinXP+BASP21.FTPオブジェクト

FTPサーバーが複数あり、定期的に指定フォルダ内のファイルリストをチェックし、指定拡張子のファイルのみ自PCに移動するツールを開発中です。

周期がばらばらなのでForm1にタイマーを複数配置し、タイマーイベントで所定の処理を行います。


Private Sub timFTP_Timer(Index As Integer)
    Dim Ftp As Object
    Set Ftp = CreateObject("BASP21.FTP")
    r1 = Ftp.Connect(パラメタ)
      :
    r2 = Ftp.GetDir(どこか)
      :
    r3 = Ftp.GetFile(どれか)
    r4 = Ftp.DeleteFile(どれか)
      :
EndSub


期待通り、timFTP(1)の処理中にtimFTP(2)のタイマーイベントが発生すればtimFTP(2)の処理は開始します。
FTPオブジェクトはちゃんと作成され、別のサーバーに同時にログインできています。
しかし、timFTP(2)の処理中はtimFTP(1)の処理は止まってしまっています。
接続先はまったく別の機体なのでそこは並列実行したいところです。


調べたところGetFileがもっとも時間がかかっていて、1ファイル1〜2秒かかっていて、最大10個のファイルを移動します。
(10個というのは1周期につき10個と制限を設けています)

このGetFile関数はコールバック関数なのですが、どうやらスレッドを停止させて待機しているよう(Form1の反応が無くなる)、そのせいで、並列処理ではなく直列処理になってしまっています。
(並列でなくても仕事はちゃんとしています)


ちなみに接続先の数は10台以上20台未満、チェック周期は10〜150秒で混在、ファイルは0〜4個(上限10個)次々に出現し、ファイルサイズは300〜600kByte程なので、衝突頻度はかなりあります。


今回はForm1のタイマーイベント内でFTPオブジェクトをインスタンスしていますが、
FTPオブジェクトの実装方法を変えれば並列処理は可能にならないものでしょうか?

あるいはBASP21.FTPオブジェクトを使わないでFTPするときのお薦めはありませんか?

シングルスレッドでも手続き的には並列動作は実現可能だと思っていますが、FTPのインターフェースを自作するのは時間とパワーががが

編集 削除
魔界の仮面弁士  2008-09-18 20:41:02  No: 101084  IP: 192.*.*.*

試していませんが、フォームに Inet コントロール(MSInet.ocx)を
複数貼り付けて使用したら、並列取得できないでしょうか。

編集 削除
我龍院  2008-09-19 08:01:09  No: 101085  IP: 192.*.*.*

この様な一つ一つの作業が非同期で行われる場合はマルチプロセス
にした方が簡単です。
先ず引数付きで起動するFTPの独立したexeを作っておいて、
メインのプログラムから引数付きで、必要な数だけ起動します。
メインに対する応答は、コールバックを使わずに、メインに上の
テキストボックスなどのハンドルを引数で渡して、直接メインの
テキストボックスに書き込むようにします。
要するに各プロセス間の結合を出来るだけ疎にしておいて、
コケているFTPサーバーや応答が遅いFTPサーバーが他の
プロセスの足を引っ張らない様にするのがコツです。

編集 削除
紅閃光  URL  2008-09-19 18:06:43  No: 101086  IP: 192.*.*.*

Inet コントロールを使えば出来そうな気がしますが、FTPのやり取りを作らなくてはならないので・・・


非同期アプリケーションというのを今の今までやったことが無かったので、
とりあえずFTP回りをクラス化して、ActiveX.EXE化してみました。

グローバル変数で読み込んでいたパラメータなどをプロパティとして渡して、
>Private Sub timFTP_Timer(Index As Integer)
としていたのを、
FTPexe.exeの中に、GetFiles()というメソッドを持ったMyFTPというクラスを呼び出すようにしてみました。

Private Sub timFTP_Timer(Index As Integer)  '@メインEXE
    Set Ftp = CreateObject("FTPexe.MyFTP")
      :
    Call Ftp.GetFiles()
      :

としたら、Ftp.GetFilesが完了するまで制御が返りません。
明らかに非同期では動いていないですね。
仕事はしていますけど。


うーん・・・
非同期で動かすにはActiveX.EXE側に制御の主体が必要のような・・・
クラスが起動したときに中で空ループを回すことが出来れば?
出来るのかな?・・・

編集 削除
我龍院  2008-09-19 19:23:31  No: 101087  IP: 192.*.*.*

Ftp.GetFiles()の処理が終わるまで、他の処理ができないのであれば、
何をしてもシングルスレッドでは無理ですね。
FtpCommandでNLISTを投げて、戻りをInternetReadFileで非同期で
読み込んで、読み込みが完了したFTPサーバーからファイルの移動処理を
行うことは可能ですが、結構面倒ですよ。
私が上に書いた方法がお奨めですが。

編集 削除
紅閃光  URL  2008-09-28 10:34:52  No: 101088  IP: 192.*.*.*

さて、BASP21.FTPオブジェクトを使い倒すことに固執して、なんとかBASP21.FTPをオブラートで包み込むがごとく非同期の並列動作可能なActiveX EXEを作ることが出来ました。

「非同期のActiveX EXEでデータのやりとりをするには?」
http://madia.world.coocan.jp/cgi-bin/VBBBS/wwwlng.cgi?print+200809/08090020.txt

やぱりMSDNは検索こそしにくいですが、第1の教科書ですね。
VB6以前の内容が平気な顔で混ざっているのがいただけませんが・・・


結局、ActiveXクラスに制御の主体を与えるために、クラス内でAPIでタイマーオブジェクトを作成しました。

少々気に食わないところもありますが(動作ではなくコード量に)、目的は達成できたので、解決とさせていただきます。

最初からBASP21.FTPオブジェクトを使わなければ、シングルプロセスシングルスレッドでも並列FTPは実現出来たかも知れませんし、むしろそっちの方が簡単だったかも。

まぁ、結果的に勉強になったので良かったですが。

どもありがとでした。

編集 削除