バイナリ連結

解決


会社合併><  2005-07-29 01:03:19  No: 91126

W2k、VB6でWinsockにて、文字+画像データを受信し表示するプログラムを開発しています。
順調に動作はしていますが、自分で見ても効率が悪いのでご教授ください。

WinSockのDataArrivalイベントで、モジュールレベルの変数mbytRecData()にバイナリデータを連結していき、一定時間後にまとめてバイナリデータを処理します。

Public mbytRecData() as Byte  ’受信データ

Private Sub wsk_DataArrival(Index As Integer, ByVal bytesTotal As Long)
         
Dim bytGetData() As Byte
Dim lngI As Long
Dim lngNextPosition As Long

    'バッファデータの取り出し
    wskCV2K(Index).GetData bytGetData, vbByte
        
        '配列未定義への対策
        On Error Resume Next
            lngNextPosition = UBound(mbytRecData) + 1
        On Error GoTo 0     
        If Err.Number <> 0  Then
            lngNextPosition = 0
        End If
        
        On Error GoTo ErrorHandler
             ReDim Preserve mbytRecData(lngNextPosition + UBound(bytGetData))
             For lngI = 0 To UBound(bytGetData)
                mbytRecData(lngNextPosition + lngI) = bytGetData(lngI)
             Next lngI
    End With
    
Exit Sub
ErrorHandler:
    If gblnDebugMode Then
        MsgBox "WinSock(" & Index & ")の受信時にエラー:" &                      Err.Description
        Resume
    End If
End Sub

こんな感じです。
当然ですが、For〜Nextの部分で受信データバイトだけ繰り返している分遅いです。
今後、通信データ量が増えた時に、より高速に処理できるようにしておきたく、高速な処理方法があればご教授ください。
何やら、ループなどしなくても1行で解決できそうなんですが、エラーばっかりでTOT


ガッ  2005-07-29 01:15:53  No: 91127

> 何やら、ループなどしなくても1行で解決できそうなんですが、エラーばっかりでTOT
ヘルプに載っているのですが…
できたら、「エラーばっかりでTOT」の
エラーメッセージや、再現できるコードなど詳細な情報が欲しいところですね。

|ω・`) 受信するだけだったらvbByte+vbArray…

※ついでに
> Public mbytRecData() as Byte  ’受信データ
と動的配列を宣言した直後に、
> lngNextPosition = UBound(mbytRecData) + 1
などとすると、怒られますw;


会社合併><  2005-07-29 02:18:44  No: 91128

質問者です。まずは訂正させてください
’************************
   'バッファデータの取り出し
    wskCV2K(Index).GetData bytGetData, vbByte
は、下記に修正させてください
   'バッファデータの取り出し
    wsk(Index).GetData bytGetData, vbByte
’*********************
ガッさん、迅速な解答ありがとうございました・
う、う〜ん、そ、そうですよねぇ〜
当然ヘルプに・・・、見つけられない俺は一体??  TOT
検索のキーワードが下手なのか、VBライブラリのみじゃ駄目なんですかね?_
まぁくだらない泣き言です、それは置いておきまして

For 〜  Nextの部分を
mbytRecData=mbytRecData  +  bytGetData
’型が一致しません。  「+」にカーソルが合ってます

***独り言****
ヘルプが2ヶ月前から「使用例」とか「プロパティ」が表示されなくなり、
リンクをクリックしても、「ランタイム  エラーが発生しました。  デバッグしますか?」って言われます、MSDNの再インストールしても直りません。
後はOSの再インストールを残すのみです><
*************


ガッ  2005-07-29 02:32:33  No: 91129

> ヘルプが2ヶ月前から「使用例」とか「プロパティ」が表示されなくなり
googleでも何とか見つかるかもしれませんね;

> mbytRecData=mbytRecData  +  bytGetData
…こんな部分見当たりませんでしたが…??
でもまぁ、mbytRecDataがByte()で、左辺値が数値だと考えれば、
Byte()に数値を代入することができないので、コンパイルエラーが発生したのだと思います。

※Byte()を受信するには、
Private Sub wsk_DataArrival(Index As Integer, ByVal bytesTotal As Long)
dim buf() as byte
wsk(index).getdata buf,vbarray+vbbyte
end sub
で出来ます…あとは、まぁ適当に。(orz


会社合併><  2005-07-29 03:00:19  No: 91130

何度もありがとうございます。
質問の仕方が悪くて申し訳ありません。
バイトの受信ができないのでは無く、バイナリ配列の連結がしたいんです><
現状のソースのままでも受信は可能で、動作もしています。(でもvbArrayはつけるべきですね^^;)
その上でバイナリ配列を連結する際に、For〜Nextより高速な連結方法を探しています。


魔界の仮面弁士  2005-07-29 04:00:45  No: 91131

> バイナリ配列の連結

ADODB.Streamをバイナリモードで開いておき、
そこにバイナリを記録するようにしてみるとか。


あっきー  2005-07-29 05:32:06  No: 91132

バイナリの連結といっても結局は配列のリサイズ、メモリブロックコピーの処理
となるので容量が増えるにつれて遅くなるのは免れません。

>ReDim Preserve mbytRecData(lngNextPosition + UBound(bytGetData))
>For lngI = 0 To UBound(bytGetData)
>  mbytRecData(lngNextPosition + lngI) = bytGetData(lngI)
>Next lngI

Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
>ReDim Preserve mbytRecData(lngNextPosition + UBound(bytGetData))
CopyMemory mbytRecData(lngNextPosition),bytGetData(0),UBound(bytGetData))+1&

とか

一番いいのは通信の初期段階で今後送信されてくる全データ量が分かれば
一回のリサイズですむので効率的ですが。


会社合併><  2005-07-29 18:27:06  No: 91133

質問者です。
皆さん、色々な意見ありがとうございます。
どうも1バイトのFor〜Nextって、効率悪い気がするんですよね^^;
ご意見を参考に、色々試してみます。

>あっきー様
現在のデータサイズは解ってはいるんですが、開発中らしく
まだまだ変更させられそうで・・^^;


ひろ  2005-07-29 18:41:12  No: 91134

とりあえず配列の大きさを出来る限り固定する方法を考えてみました。

案1:最初から大きめの配列(数KBぐらい)をバッファとして用意してき、バッファのどの位置まで受信データが入っているかを管理することで ReDim Preserveの実行回数を減らす。

案2:プロトコル仕様に手を入れて、1回に送信されるデータサイズの上限を定めるか、データの先頭にデータサイズ情報を格納する


魔界の仮面弁士  2005-07-29 18:57:19  No: 91135

バイナリの連結自体は、バイナリストリームを使った方が
簡単だと思いますよ。ReDim等が不要な分、扱いやすいですし。

具体的には、ActiveX Data Objects を参照設定しておき、

Private BinaryBuffer As ADODB.Stream
Private Sub Form_Load()
    Set BinaryBuffer = New ADODB.Stream
    BinaryBuffer.Type = adTypeBinary
    BinaryBuffer.Open
End Sub

という感じで、バイナリストリームを作成しておいて、
    BinaryBuffer.Write バイト配列
として、バイト配列を記録していきます。
(Writeするたび、ストリームの末尾にバイナリが追加される)

そして、取り出す時にはこんな感じ。

《全データを一括して取り出す場合》
Dim Result() As Byte
BinaryBuffer.Position = 0     '先頭に戻してから
Result = BinaryBuffer.Read()  '全データを一括読み込み

《10バイト目〜13バイト目の4バイト分を取り出す場合》
BinaryBuffer.Position = 10
Result = BinaryBuffer.Read(4)

# 読み込み作業後、さらに追記が必要な場合は、
# Positionを末尾に戻しておく事を忘れずに。


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

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






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