2

TcpClients を処理するクラスがあります。クラスがすべきことは次のとおりです。

    while the other end has not done a graceful close or we are stopping
    {
        receive a request
        process it
        send response
    }

他のクライアントがいつリクエストを送信するかわからないため、タイムアウトを設定して読み取りを行うことはできません。

    While Not Me.Stopping()
        Try
            If tcpClient.Available >= My.Settings.minimumModBusTcpFrameSize Then
                processer = New MessageProcesser(Me, tcpClient)
                processer.ProcessMessage()
            End If
        Catch ex As TimeoutException
            ''#Do not nothing, the current message will timeout on origin too.
        End Try
    End While

このアプローチの問題は、クライアントが Close() へのリモート呼び出しをいつ行ったかがわからないことです。

この問題を解決する方法はありますか?

4

5 に答える 5

3

タイムアウトを使用できない理由がわかりませんRead...読み取りがタイムアウトした場合は再試行できますが、Read0 を返す場合は接続が閉じられています。

編集:はい、ここで動作を確認しました-さらに読むと実際に失敗するようです。それは本当に奇妙です...私はここに私の答えを残しておきます.

于 2009-12-29T10:46:46.017 に答える
2

Just a test to show the problem found implementing the Jon Skeet answer:

Public Class Form1

Private m_listener As Net.Sockets.TcpListener
Private m_client As Net.Sockets.TcpClient
Private m_stopping As Boolean

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    Dim data As Byte()
    Dim dataLength As Integer

    ReDim data(512)

    m_listener = New Net.Sockets.TcpListener(Net.IPAddress.Any, 502)
    m_listener.Start()
    m_client = m_listener.AcceptTcpClient()

    m_client.GetStream().ReadTimeout = 1000
    m_client.GetStream().WriteTimeout = 1000

    While Not m_stopping
        Try
            dataLength = m_client.GetStream.Read(data, 0, data.Length)
            If dataLength = 0 Then
                MsgBox("Disconnected")
            End If
        Catch ex As Exception When TypeOf (ex) Is TimeoutException OrElse (Not ex.InnerException Is Nothing AndAlso TypeOf (ex.InnerException) Is Net.Sockets.SocketException AndAlso DirectCast(ex.InnerException, Net.Sockets.SocketException).ErrorCode = 10060)
            ''# Just retry
        End Try
    End While
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    m_stopping = True
End Sub
End Class

If you connect with a Telnet client you will get an InvalidOperationException because the socket has been closed after the timeout time (one second).

于 2009-12-29T11:55:20.967 に答える
1

解決策はこの質問にあります:

反対側が閉じるか、.Netで停止するまでTcpClientで読み取る方法

于 2010-01-04T14:32:44.743 に答える
1

同様のケースがありますが、udpclient を使用しています。リモート エンドポイントが使用できなくなったかどうかを確認するために、SocketException をキャッチしています。

    While True
        Try
            Dim RecievedBytes As Byte() = udp.Receive(mRemoteIP)
            mMessage = System.Text.Encoding.ASCII.GetString(RecievedBytes)
            RaiseEvent MessageRecieved()
        Catch ex As Sockets.SocketException
            MsgBox("Your firewall may be blocking you from recieving messages")
        End Try
    End While
于 2009-12-29T11:05:12.907 に答える
1

Jon は既に回答していますが、クライアントを制御できる場合は、「接続を閉じてください」という意味のリクエストを追加することもできます。そのため、「正常に閉じる」ことを試みることができ、Jon の「自動検出」アプローチを使用できます。クライアントは接続をきちんと閉じることができません。

于 2009-12-29T10:55:19.193 に答える