- - PR -
VB.NET ActiveモードでのFTP処理について
1
投稿者 | 投稿内容 | ||||||||
---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2005-07-11 21:15
いつもお世話になっております。
VB.NETで簡易FTPツールを作成しております。 備わっている機能は、「リストの一覧表示/ファイルのUPLOAD/DOWNLOAD」と単純なものです。 Passiveモードで処理を行う場合であれば、ネット上にサンプルがたくさんありましたので容易に開発できました。 しかしActiveモードで処理を行う場合のサンプルが少なく困っております。 【環境】 VB.NET FrameWork1.1 Windows2003Server 【問題点】 Activeモードでデータコネクションを張りLIST等の要求を発行したはずなのに、TcpListener.Pendingメソッドにてfalseが帰ってくることがよくある。 (※何回かFTPサーバーに接続/切断を繰り返す) 【ソース】 @FTPサーバーへの接続 mclsCtrlConSocket = New Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) lclsCtrlCon = New IPEndPoint(Dns.Resolve("サーバー名").AddressList(0), 21) mclsCtrlConSocket.Connect(lclsCtrlCon) 〜〜〜〜〜接続判定処理は省略 Aデータコネクションの確立 Dim lipAddress As IPAddress = Dns.Resolve(Dns.GetHostName()).AddressList(0) testtcpListener = New TcpListener(lipAddress, 0) testtcpListener.Start() lclsDataConIPEP = CType(testtcpListener.LocalEndpoint, IPEndPoint) lsubSendCommand("PORT " & PortParam(lclsDataConIPEP.Port)) Private Function PortParam(ByVal port As Integer) As String Dim localhost As IPHostEntry = Dns.Resolve(Dns.GetHostName()) Dim IPAddress As IPAddress = localhost.AddressList(0) Dim address As String = IPAddress.ToString().Replace(".", ",") Dim i1 As Integer = CInt(port / 256) Dim i2 As Integer = port Mod 256 Return address + "," + i1.ToString() + "," + i2.ToString() BLIST命令発行 lbytCommandBytes = ASCII.GetBytes("LIST /TEST") mclsCtrlConSocket.Send(lbytCommandBytes, lbytCommandBytes.Length, 0) C処理判定 if testtcpListener.Pending then ※←-----ここでfalseになる lclsDataConSocket = testtcpListener.AcceptSocket() End If D終了処理 testtcpListener.Stop() testtcpListener = Nothing lclsDataConSocket.Shutdown(SocketShutdown.Both) lclsDataConSocket.Close() lclsDataConSocket = Nothing 途中のソースは省略しましたが、大まかな流れはこのようになっております。 説明で分かりにくい所があるとは思いますが、ご存知の方がいらっしゃったらご教授して頂きたく思います。 宜しくお願い致します。 | ||||||||
|
投稿日時: 2005-07-12 06:52
FTP Serverにコマンドを発行した後、応答が帰ってくるまでには多少の時間がかかります。コマンド発行後、直ちに接続要求の有無を確認して処理していたのでは、Server側での処理が早かったときは動作するかもしれませんが、ちょっと時間がかかっている場合にはPendingでFalseが帰ってくるでしょうね。 以下の様にPendingがTrueを返すまで、繰り返してください。
| ||||||||
|
投稿日時: 2005-07-12 09:58
なるほど、応答までの時間を考慮するべきなんですね。 指摘くださった方法で試してみることにします。 甕星様、ありがとうございました。 | ||||||||
|
投稿日時: 2005-07-12 11:49
TcpListner.AcceptSocket/AcceptTcpClientメソッドは、接続要求がキューにない間はスレッドをブロックします。
http://www.microsoft.com/japan/msdn/library/default.asp?url=/japan/msdn/library/ja/cpref/html/frlrfsystemnetsocketstcplistenerclasstopic.asp ですからこの場合わざわざPendingで接続要求をチェックする必要もないでしょう。 そのままAcceptしてやれば繋がるまで待ってくれます。 | ||||||||
|
投稿日時: 2005-07-12 13:09
Hongliang様
msdn読ませて頂きました。 スレッドをブロックするとは気づきませんでした。。。 そこで今度はPendingをはずして実行しました。 LIST等の命令を発行し、AcceptSocket() を実行してブロック状態に入った後でも、ず〜っとブロックされてしまう状態となってしまいます。 (キューに入っていない?) 実際の命令発行は以下の通りになっています。 Dim lbytCommandBytes As Byte() lbytCommandBytes = ASCII.GetBytes("LIST /TEST") mclsCtrlConSocket.Send(lbytCommandBytes, lbytCommandBytes.Length, 0) (※mclsCtrlConSocketは制御用のコネクション) このソケットのReceive結果を取ってみると 200 PORT command successful. 150 Opening ASCII mode data connection for /bin/ls. のどちらかである為に、命令は受け付けてもらっていると思われます。 環境面も含め、もうちょっと調べたいと思っております。 。。。顧客先で使用している負荷分散装置がPASVモードを受け付けない仕様になっているなんて・・・しんどぃ _| ̄|○ | ||||||||
|
投稿日時: 2005-07-12 15:18
ネット上でなんとかサンプルを見つけました。
http://members.jcom.home.ne.jp/1213687801/cs/general/ftp1.html (※Activeモードで、LIST命令を実行。C#で作成されています) これを連続で100回実行した所、正常に動作されました。 そこで、これをVB.NET用に自分で置き換えた所、連続100回実行の途中で、AcceptSocket() 部にてまたブロックされてしまいました。 こうなるとコーディングの問題かな?と思われます。 ちなみにAcceptSocket() を発行するまでの処理をVB.NETで置き換えたものは以下の通りです。 Dim HostName As String = Dns.GetHostName() Dim ThisHost As IPHostEntry = Dns.GetHostByName(HostName) Dim listener As TcpListener = New TcpListener(ThisHost.AddressList(0), 0) Dim datasocket As Socket = Nothing Dim retcode As Integer = 0 Dim Output As String = "" Try listener.Start() ''PORT command Dim ep As IPEndPoint = CType(listener.LocalEndpoint, IPEndPoint) retcode = ExecCmd("PORT " & PortParam(ep.Port) & ControlChars.CrLf, Output) If (retcode = 0) Then Return retcode ''引数で指定された command retcode = ExecCmd(cmd, Output) If (retcode = 0) Then Return retcode ''データ受信 Dim recvData(1024) As Byte Dim sb As StringBuilder = New StringBuilder Dim recvSize As Integer Console.WriteLine("接続要求があるか?:" + listener.Pending().ToString()) datasocket = listener.AcceptSocket() 【主な修正内容】 @C#でExecCmd("PORT " & PortParam(ep.Port) & "\\r\\n", Output) →ExecCmd("PORT " & PortParam(ep.Port) & ControlChars.CrLf, Output) AC#でbyte[] recvData=new byte[1024]; →Dim recvData(1024) As Byte BC#で int i1=port/256; int i2=port%256; →Dim i1 As Integer = port / 256 Dim i2 As Integer = port Mod 256 ソースコードばかり載せてしまい、申し訳ありません。 [ メッセージ編集済み 編集者: かえで 編集日時 2005-07-12 17:01 ] | ||||||||
|
投稿日時: 2005-07-12 18:04
自己レスです。
解決しました。 クライアント側のポート算出が間違っていたのが原因でした。 × Dim i1 As Integer = CInt(port / 256) ○ Dim i1 As Integer = port ¥ 256 この為にPORTコマンドで送り出したポートと実際のクライアントでの受け口がずれてしまってたようです。 皆様方には大変お手数をおかけしました。 |
1