VBでは不可能?WinsockのDataArrivalでフリーズしてしまう


てぃん  2006-03-14 13:24:42  No: 94575

タイトル通りなのですが、
Winsockで10M程度のファイルの転送を試みたのですがフリーズしてしまいます。
DataArrivalイベントにDoEventsを設置してみましたがスタック不足という変なエラーが出てしまいました。
小さいファイルならフリーズしないのですがやはりVBでは不可能ということなのでしょうか?


ガッ  2006-03-14 17:51:39  No: 94576

とりあえず
・TCPはストリームソケット
・A,B,Cを送信したら、x,A+B+C前半,C後半+yの様に受信されることもある
です

あと、スタックが不足するのは、イベントプロシージャがDoEventsによって再帰的に呼び出されているからだと思います
例)
private sub winsock_dataarrival(..)
'何か処理
DoEvents 'このdoeventsでdataarrivalイベントが再度発生するかも
end sub
上の例では、
DataArrival[1]
  DataArrival[2]
    ...
      DataArrival[n]
とスタックを延々と食いつぶしていきます

これ以上のことは実際のコードを見ないとわかりませんw;


てぃん  2006-03-14 19:05:43  No: 94577

DataArrivalでWinsock1.GetData b(), vbArray + vbByte
としてひたすら受信しています。
実際には結合も行いますが、今回はフリーズが問題なのでフリーズの解決策をご教示頂けませんでしょうか?


我龍院忠太  2006-03-14 20:25:07  No: 94578

>今回はフリーズが問題なのでフリーズの解決策をご教示頂けませんでしょうか?
詳しいフリーズの定義は解りませんが、この場合受信処理が忙しくて、Windowsの方に
処理が回らないのでしょう、通常言われるフリーズとはチョッと違うような気がします。
この様な場合は既にやられた様に、DoEventsを入れてWindowsに処理を回しますが、
そうするとガッさんが書かれているように、DataArrivalの中で更にDataArrivalイベント
が起こって、結果スタックオーバーフローが発生します。
(こう言うのは再帰って言うのかな、再帰は自分自身を呼び出すことなんだけど
この場合は、イベント割り込み処理中に同じイベントの割り込みが入るだけだと
思いますが。)
これを避けるためには、データーを送る側で一度にデーターを送らずに、1kとか
そんな単位でデーターを区切って送り、受け取り側は、データーを処理し終えた
段階で送り側に次の送信要求を出すとかすれば良いのでは。
もしデーターの送り側のコードに手を入れられないのであれば、受信をDataArrivalイベント
で行うのではなく、ポーリングでやるとか、DataArrivalイベントの最初にフラグを立てておき
処理中での割り込み処理を防ぐなどの方法も有りそうです。


123  2006-03-14 21:13:56  No: 94579

Winsock1.GetData b(), vbArray + vbByte
この処理はサイズが大きくなると、かなりの時間を費やすようになります。
受信するバイと数が分かっているなら最初にメモリを確保しておいた方が
良いでしょう


123  2006-03-14 21:15:00  No: 94580

すいません、この処理というのは下記のこと
>実際には結合も行いますが


魔界の仮面弁士  2006-03-14 21:20:37  No: 94581

バイナリデータを結合していく場合は、Byte配列を使うよりも、
Binaryモードの Stream に蓄えていく方が効率が良いかも。


てぃん  2006-03-14 23:34:32  No: 94582

たくさんのご返信有難う御座います。

>我龍院忠太さん
ポーリングで行う場合DataArrivalイベントの頭に、
Do While flg = True: DoEvents :Loop
とすればいいのかなと考えましたが、
この場合待機中に次のDataArrivalイベントが発生してしまい、
次のデータを受信する際に次のデータ以外のデータを受信してしまいませんか?
この待機の処理自体に誤りがあるのでしょうか?

>123さん
ご教示有難う御座います。
結合用の変数にサイズ分の要素数を用意しておき繋いでいくという意味でしょうか?
受信用の変数b1()
結合用の変数b2()
受信データサイズ10Mとする

'---Generalにグローバル変数を宣言
Dim gb() As Byte

'---フォームロード時の処理
lngData = 1024 * 1024 * 10
Redim gb(lngData)

'---DataArrivalの処理
Dim b() As Byte
Winsock1.GetData b(), vbArray + vbByte

ここまでは浮かんだのですがバイト配列の結合時の処理はどうしたら良いのでしょうか?
以前の記事でb()のデータをFor分でループさせ1byteずつ取り出すという物を見かけましたが効率が悪く、
後述致しますが魔界の仮面弁士さんがADODB.Streamを使用した連結法は高速だったのですが問題がありまして・・。

>魔界の仮面弁士さん
BinaryモードのStreamというのはADODB.Streamのことで合っていますか?
以前魔界の仮面弁士さんのサンプルを参考にテストしようとしたのですが、
ADODBはAccessがインストールされた環境でないと使用できないという記事を見かけました。
Accessがインストールされていない環境で使用する方法などありますでしょうか?


てぃん  2006-03-14 23:35:31  No: 94583

訂正です。
>受信用の変数b1()
>結合用の変数b2()
受信用の変数b()
結合用の変数gb()


てぃん  2006-03-14 23:44:15  No: 94584

何度も申し訳ないです。
まさかこんな質問が既出とは考えず調べていませんでした・・。
過去ログを検索したところ何件もHITしました・・申し訳ない・・。
魔界の仮面弁士さんありがとうございました。
ADODB.Streamを使用する方法に関しては把握できました。


我龍院忠太  2006-03-15 03:27:03  No: 94585

>この待機の処理自体に誤りがあるのでしょうか?
ポーリングのルーチンはDataArrivalイベント以外の所に書きます、
どこに書くかはそれぞれのコードによって違いますが、通信スタート
ボタンのクリックイベントの中とか。
ループの中にはSleep(1)位を入れて置きます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加