这个问题有点令人困惑,我一遍又一遍地尝试使用Google和Stack Overflow来寻找答案。我在VB.NET中编写了一个Windows服务,它使用TcpListener类来监听连接应用程序。这是一个相当简单的服务,只允许应用程序的多个实例将UDP数据报发送到我们的端口7000上监听的仪器。服务的原因是因为它必须在端口7001上监听来自仪器的UDP数据报,并将它们转发使用TCP连接到客户端应用程序。
无论如何,在我的问题上。当客户端应用程序是使用TcpClient连接到服务的VB.NET应用程序时,一切运行正常。当客户端应用程序关闭其TCP连接时,服务中的TcpClient不能再接收数据(这会导致异常,从而提示服务关闭并删除有问题的TcpClient)。到目前为止一切都很好。
当客户端是使用Winsock控件连接到服务的VB6应用程序时,一切都很好,直到Winsock控件关闭连接。此时,TcpClient.Connected属性仍为True,尝试读取流不会导致异常。本质上,该服务仍然认为连接是开放的。更糟糕的是,网络流中BeginReceive函数的回调函数不断被调用,因为TcpClient被假定为关闭。这会导致Process Explorer显示使用100%处理器(或核心)的服务。经过进一步调查,Process Explorer将连接状态报告为CLOSE_WAIT。
也许在TcpClient类中有另一个属性或方法,我可以检查连接是关闭还是关闭。但到目前为止我还没有找到它。这是代码的副本供大家查看。也许你可以看到我错过了什么。感谢您花时间阅读本文。
' Receives the TCP packet from the clients, processes them and forwards them on as requested.
Private Sub ReceiveTcpPacketCallback(ByVal AsyncResult As System.IAsyncResult)
' Retrieve the asynchronous state for the callback.
Dim AsyncState As TcpAsyncState = CType(AsyncResult.AsyncState, TcpAsyncState)
' Get the TCP client associated with this state.
Dim TcpClient As System.Net.Sockets.TcpClient = AsyncState.TcpClient
Try
If TcpClient.Connected Then
Dim CommandData As String
' Get the network stream associated with the TCP client that sent the packet.
Dim NetworkStream As System.Net.Sockets.NetworkStream = TcpClient.GetStream
' Sync lock the receive buffer to ensure that no other threads are touching it.
SyncLock m_pReceiveBuffer
' End the read to retrieve the data into the locked buffer.
Dim DataLength As Integer = NetworkStream.EndRead(AsyncResult)
' Convert the bytes retrieved into a string using ASCII encoding.
CommandData = System.Text.Encoding.ASCII.GetString(m_pReceiveBuffer, 0, DataLength)
End SyncLock
' Process the command data that was sent from the TCP client and process the command if complete.
If AsyncState.ProcessCommandData(CommandData) Then ProcessCommandInformation(AsyncState)
' Continue listening for more commands from the client.
NetworkStream.BeginRead(m_pReceiveBuffer, 0, m_pReceiveBuffer.Length, AddressOf ReceiveTcpPacketCallback, AsyncState)
Else
' Attempt to close the TCP client and remove it from the list.
TcpClient.Close()
If m_pTcpClients.Contains(TcpClient) Then m_pTcpClients.Remove(TcpClient)
End If
Catch ex As Exception
Dim Message As New System.Text.StringBuilder
' If an exception occurs, assemble the message to write to the event log.
Message.Append(Date.Now.ToString).Append(","c).Append("ReceiveTcpPacketCallback Exception,")
Message.Append("Error Receiving Command From TCP Client,")
Message.Append(ex.Source).Append(","c).Append(ex.Message)
' Write the message to the event log.
Me.EventLog.WriteEntry(Message.ToString)
' Attempt to close the TCP client and remove it from the list.
TcpClient.Close()
If m_pTcpClients.Contains(TcpClient) Then m_pTcpClients.Remove(TcpClient)
End Try
End Sub