[リストへもどる]   [VBレスキュー(花ちゃん)]
一括表示

投稿時間:2007/04/18(Wed) 18:02
投稿者名:戸豚
Eメール:
URL :
タイトル:
TCP送受信がぶつかると固まる?
Windows 2000/XP Pro、VB6.0 SP6でWinsockコントロールを使うツールを組んでいます。

通信相手はマイコンボードで、リンク確立確認のために定期的にポーリングメッセージを送ってきます。

ところが、このポーリングメッセージ受信時に近いタイミングで送信を行なうと(送信処理中に受信ありか、受信中に送信処理を始めたかまではわかりませんでしたが)VB6.0のプロセスだけがフリーズします。
タスクマネージャーのパフォーマンスを見るとCPU使用率が100%のままになります。

これの回避策はないんでしょうか?
WinsockAPIにはブロッキングとノンブロッキングの違いがある、というのはわかったんですが、Winsockコントロールはノンブロッキングではないんでしょうか?


送受信に関わるコードを載せておきます。


--------- フォームの処理 -----------------

Private Sub PortOpen_Click()
  ' コネクト
    Winsock1.Protocol = sckTCPProtocol
    Winsock1.RemoteHost = remoteIP
    Winsock1.remotePort = remotePort
    Winsock1.LocalPort = 0
    Winsock1.Connect
End Sub

Private Sub Winsock1_Connect()
  ' コネクトイベント

  Dim sndData(1) As Byte

  sndData(0) = CMDCODE_LINKESTABLISH_REQ
  sndData(1) = getSessionNumber()

  ' 通信開始要求
    Winsock.SendData(sndData)
    bBusyIsWinSock = True
End Sub

Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long)
    ' 受信イベント.
    Static recvData() As Byte
    Winsock1.GetData recvData, vbArray + vbByte, bytesTotal
    Call addTcpRecivieData(recvData)
End Sub

Private Sub Winsock1_Error(ByVal Number As Integer, Description As String, ByVal Scode As Long, ByVal Source As String, ByVal HelpFile As String, ByVal HelpContext As Long, CancelDisplay As Boolean)
  ' エラー

    Debug.Print ""
    Debug.Print "WinSock error"
    Debug.Print "WinSock State=" & Winsock1.state
    Debug.Print "Number      = " & Number
    Debug.Print "Description = " & Description
    Debug.Print "Scode       = " & Hex(Scode)
    Debug.Print "Source      = " & Source
    Debug.Print ""
    
    Debug.Print ".LocalHostName = " & Winsock1.LocalHostName
    Debug.Print ".localIP       = " & Winsock1.localIP
    Debug.Print ".LocalPort     = " & Winsock1.LocalPort
    Debug.Print ".name          = " & Winsock1.name
    Debug.Print ".Protocol      = " & Winsock1.Protocol
    Debug.Print ".RemoteHost    = " & Winsock1.RemoteHost
    Debug.Print ".RemoteHostIP  = " & Winsock1.RemoteHostIP
    Debug.Print ".RemotePort    = " & Winsock1.remotePort
    Debug.Print ".SocketHandle  = " & Winsock1.SocketHandle

    MsgBox Description, vbOKOnly, "ERROR"

    Winsock1.Close
    Debug.Print "Winsock State=" & Winsock1.state
End Sub

Private Sub Winsock1_SendComplete()
    ' 送信完了
    bBusyIsWinSock = False
End Sub


------------- 実際に送信処理を行うモジュールの処理 -------------

Public Function addTcpSendingData(ByRef sndData() As Byte) As Boolean

    If sckConnected = Form1.Winsock1.state Then

        Do
            DoEvents
        Loop While Form1.bBusyIsWinSock
    
        Call Form1.Winsock1.SendData(sndData)
        Call Form1.setWinsockBusy
        addTcpSendingData = True
    Else
        addTcpSendingData = False
    End If
End Function

投稿時間:2007/04/19(Thu) 09:21
投稿者名:GOD
Eメール:
URL :
タイトル:
Re: TCP送受信がぶつかると固まる?
>        Do
>            DoEvents
>        Loop While Form1.bBusyIsWinSock
>
bBusyIsWinSockがTrueになっていて無限ループになっていることは無いですか?

投稿時間:2007/04/19(Thu) 09:53
投稿者名:戸豚
Eメール:
URL :
タイトル:
Re^2: TCP送受信がぶつかると固まる?
> >        Do
> >            DoEvents
> >        Loop While Form1.bBusyIsWinSock
> >
> bBusyIsWinSockがTrueになっていて無限ループになっていることは無いですか?

試しに

Do
  DoEvents
Loop

と変えたらデータ送信しないですけど、フリーズしませんでした。
アプリがフリーズときはほかのアプリのウィンドウを重ねてから外すと、重なった部分は再描画されないんですが、Do〜Loopで無限ループしているときは再描画されますしコマンドボタンなども反応します。

投稿時間:2007/04/19(Thu) 11:21
投稿者名:GOD
Eメール:
URL :
タイトル:
Re^3: TCP送受信がぶつかると固まる?
> と変えたらデータ送信しないですけど、フリーズしませんでした。
> アプリがフリーズときはほかのアプリのウィンドウを重ねてから外すと、重なった部分は再描画されないんですが、Do〜Loopで無限ループしているときは再描画されますしコマンドボタンなども反応します。
>
すみません。固まるはフリーズのことでしたか。
あと、Call Form1.setWinsockBusyはなにをしているのでしょうか。中でループとか使ってますか?

# ループ中にDoEventsが含まれていなければ、ウィンドウの再描画とかしなくなりますね。

投稿時間:2007/04/19(Thu) 13:00
投稿者名:戸豚
Eメール:
URL :
タイトル:
Re^4: TCP送受信がぶつかると固まる?

> すみません。固まるはフリーズのことでしたか。
> あと、Call Form1.setWinsockBusyはなにをしているのでしょうか。中でループとか使ってますか?

setWinsockBusy() はフラグのチェックとセットをしてます。

Public Function setWinsockBusy() as Boolean
    If bBusyIsWinSock = True Then
        Debug.Print "送信中の送信要求."
    End if
    setWinsockBusy = bBusyIsWinSock
    bBusyIsWinSock = True
End Function

送信中の送信かと疑ってたんでチェック用のコードを入れてるんですがこのプロシージャの Debug.Print は呼ばれません。

# Winsock APIをノンブロッキングモードで使う方がいいのかも、とか想い始めてますが
# はてさてウィークエンドプログラマの余技でできるモノやら…

投稿時間:2007/04/25(Wed) 15:02
投稿者名:戸豚
Eメール:
URL :
タイトル:
Re^5: TCP送受信がぶつかると固まる?
経過報告です。

Winsock APIを直接叩くので、 VB マガジンのサンプル http://www.int21.co.jp/pcdn/vb/norioli
b/ を使ってみました。
フリーズしなくなりましたが、マイコンボードからのレスポンスを認識しませんでした・・・
ぐるっと回り道して最初のトラブルに戻ってきた状態です。

API定義で As Any宣言の変数にはByte配列が渡せないとか小さい(と思いたい)障害はありますが何
はともあれ一歩前進(と信じて)次ぎはレスポンスを認識するように挑戦です。

GODさん、アドバイス有難う御座いました。

投稿時間:2007/04/25(Wed) 15:06
投稿者名:魔界の仮面弁士
Eメール:
URL :
タイトル:
Re^6: TCP送受信がぶつかると固まる?
> As Any宣言の変数にはByte配列が渡せないとか

API 定義が ByRef x As Any な引数にバイナリを渡すなら、
 Dim B() As Byte
 B = [バイナリ]
 Call Foo(B(0))
のように、バイト配列の先頭要素を参照渡しするか、
 Call Foo( ByVal VarPtr(B(0)) )
のように、先頭要素のアドレスを値渡しすれば良いかと。

投稿時間:2007/04/26(Thu) 09:27
投稿者名:戸豚
Eメール:
URL :
タイトル:
Re^7: TCP送受信がぶつかると固まる?
> API 定義が ByRef x As Any な引数にバイナリを渡すなら、
>  Dim B() As Byte
>  B = [バイナリ]
>  Call Foo(B(0))
> のように、バイト配列の先頭要素を参照渡しするか、
>  Call Foo( ByVal VarPtr(B(0)) )
> のように、先頭要素のアドレスを値渡しすれば良いかと。


C言語の char* を VBでどう表現するかで引っかかっていたのですが無事解決しました。
ありがとう御座います。