我有一个处理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()进行了远程调用。
有没有办法解决这个问题?
答案 0 :(得分:3)
我不明白为什么你不能超时Read
...如果读取超时你可以重试它,而如果Read
返回0那么连接已经闭合。
编辑:是的,我已经确认了这里的行为 - 进一步的阅读确实似乎失败了。这真的很奇怪...我在这里留下我的答案,因为我觉得应该是合适的 - 希望在某些时候我会有时间再次调查它。
答案 1 :(得分: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,因为套接字已在超时时间(一秒)后关闭。
答案 2 :(得分:1)
Jon已经回答了,但是如果您已经控制了客户端,那么您还可以添加一个“请关闭连接”的请求,这样您就可以尝试“优雅关闭”,只需使用Jon的“自动检测”如果客户端未能整齐地关闭连接,则接近。
答案 3 :(得分: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
答案 4 :(得分:1)