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一个超时......如果读取超时,你可以重试它,而如果Read返回 0 则连接已关闭。

编辑:是的,我已经确认了这里的行为——进一步阅读确实似乎失败了。这真的很奇怪......我将我的答案留在这里,因为我觉得应该是合适的 - 希望在某个时候我有时间再次调查它。

于 2009-12-29T10:46:46.017 回答
2

只是一个测试来显示发现实现 Jon Skeet 答案的问题:

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

如果您使用 Telnet 客户端连接,您将收到 InvalidOperationException,因为在超时时间(一秒)之后套接字已关闭。

于 2009-12-29T11:55:20.967 回答
1

乔恩已经回答了,但是如果您可以控制客户端,那么您还可以添加一个表示“请关闭连接”的请求,这样您就可以尝试“优雅关闭”,如果客户端未能整齐地关闭连接。

于 2009-12-29T10:55:19.193 回答
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

解决方案是在这个问题上:

如何使用 TcpClient 读取直到对方关闭或我们在.Net 中停止

于 2010-01-04T14:32:44.743 回答