2009-12-29 63 views
2

我有一个类可以处理TcpClients。什么类应该做的是:如何在.NET中关闭另一端时关闭TcpClient?

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()的远程调用。

有没有办法解决这个问题?

回答

3

我不明白为什么你不能用超时执行Read ......如果读取超时,你可以重试它,而如果Read返回0,那么连接已经关闭。

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

+0

我发现与读取和IOException异常,而不是TimeoutException异常的问题。我只是在调查,并会返回结果。 – 2009-12-29 11:19:54

+0

看起来像当我有一个超时TcpClient断开连接,并关闭套接字,所以我不能再次重试读取。 – 2009-12-29 11:51:31

1

Jon已经回答了,但是如果你控制了客户端,那么你也可以添加一个请求,意思是“请关闭连接”,这样你可以尝试一个“优雅关闭”,并且只需要使用Jon的“自动检测“方法,如果客户端无法关闭连接整齐。

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 
2

只是一个测试,以显示发现实施乔恩斯基特答案的问题:

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,因为在超时时间(一秒)之后套接字已经关闭。