首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > .NET > VB Dotnet >

Socket服务端关闭有关问题

2012-02-10 
Socket服务端关闭问题源代码(VB.NET2005)ImportsSystem.NetImportsSystem.Net.SocketsImportsSystem.Threa

Socket服务端关闭问题
源代码(VB.NET   2005)
Imports   System.Net
Imports   System.Net.Sockets
Imports   System.Threading
Imports   System.Text

Public   Class   frmMain
        Private   objSocketServer   As   SocketServer

        Public   Sub   New()
objSocketServer   =   New   SocketServer()
        End   Sub

        Private   Sub   btnStart_Click(ByVal   sender   As   System.Object,   ByVal   e   As   System.EventArgs)   Handles   btnStart.Click
                objSocketServer.BindIP   =   txtInternetIP.Text.Trim()
                objSocketServer.BindPort   =   Integer.Parse(txtDataListenPort.Text)
                objSocketServer.Run()
        End   Sub

        Private   Sub   btnStop_Click(ByVal   sender   As   System.Object,   ByVal   e   As   System.EventArgs)   Handles   btnStop.Click
                objSocketServer.StopRun()
        End   Sub
End   Class

Public   Class   SocketServer
        Private   m_BindIP   As   String
        Private   m_BindPort   As   Integer
        Private   RunState   As   Boolean
        Private   aryClientList   As   ArrayList
        Private   sckServer   As   Socket
        'Private   thdAccept   As   Thread
        Private   Done   As   ManualResetEvent

        Public   Sub   New()
                m_BindIP   =   " "
                m_BindPort   =   0
                RunState   =   False
                aryClientList   =   New   ArrayList()
                Done   =   New   ManualResetEvent(False)
        End   Sub

        Public   Property   BindIP()   As   String
                Get
                        Return   m_BindIP
                End   Get
                Set(ByVal   value   As   String)
                        m_BindIP   =   value
                End   Set
        End   Property

        Public   Property   BindPort()   As   Integer
                Get
                        Return   m_BindPort


                End   Get
                Set(ByVal   value   As   Integer)
                        m_BindPort   =   value
                End   Set
        End   Property

        Public   Sub   StopRun()
                RunState   =   False
                sckServer.Close()
                'thdAccept.Abort()
        End   Sub

        Public   Sub   Run()
                Dim   ipLocal   As   IPAddress
                Dim   intListenPort   As   Integer
                Dim   ipepServer   As   IPEndPoint

                ipLocal   =   IPAddress.Parse(m_BindIP.Trim())
                intListenPort   =   m_BindPort
                ipepServer   =   New   IPEndPoint(ipLocal,   intListenPort)
                sckServer   =   New   Socket(AddressFamily.InterNetwork,   SocketType.Stream,   ProtocolType.Tcp)
                Try
                        sckServer.Bind(ipepServer)
                        sckServer.Listen(100)
                        Dim   thdAccept   As   New   Thread(AddressOf   ThreadBeginAccept)
                        thdAccept.Start()
                Catch   ex   As   Exception
                        MessageBox.Show( "错误描述:   "   &   ex.Message   &   vbCrLf   &   "错误源:   "   &   ex.Source,   "错误 ",   MessageBoxButtons.OK,   MessageBoxIcon.Error)
                        Exit   Sub
                End   Try
        End   Sub

        Private   Sub   ThreadBeginAccept()
                RunState   =   True
                Do
                        Done.Reset()
                        sckServer.BeginAccept(New   AsyncCallback(AddressOf   OnConnectRequest),   sckServer)
                        Done.WaitOne()
                Loop   While   RunState   =   True


        End   Sub

        Private   Sub   OnConnectRequest(ByVal   ar   As   IAsyncResult)
                Done.Set()
                Dim   Listener   As   Socket   =   CType(ar.AsyncState,   Socket)
                NewConnection(Listener.EndAccept(ar))
                Listener.BeginAccept(New   AsyncCallback(AddressOf   OnConnectRequest),   Listener)
        End   Sub

        Private   Sub   NewConnection(ByVal   sckClient   As   Socket)
                Dim   objSocketClient   As   New   SocketClient(sckClient)
                Debug.Print(objSocketClient.Sock.RemoteEndPoint.ToString()   &   "   已连接 "   &   vbCrLf)
                aryClientList.Add(objSocketClient)
                objSocketClient.RecieveCallback(Me)
        End   Sub

        Public   Sub   OnRecieveData(ByVal   ar   As   IAsyncResult)
                Dim   objSocketClient   As   SocketClient
                objSocketClient   =   CType(ar.AsyncState,   SocketClient)
                Dim   bytRecieveData()   As   Byte   =   objSocketClient.GetRecieveData(ar)
                '判断远程客户端是否断开连接
                If   bytRecieveData.Length   <   1   Then
                        Debug.Print(objSocketClient.Sock.RemoteEndPoint.ToString()   &   "   已断开 "   &   vbCrLf)
                        objSocketClient.Sock.Close()
                        aryClientList.Remove(objSocketClient)
                        Exit   Sub
                End   If
                Dim   x   As   String   =   Encoding.ASCII.GetString(bytRecieveData).Trim()
                Debug.Print(vbCrLf   &   "接收数据: "   &   x   &   vbCrLf)
                If   Left(x,   x.Length)   =   "123456 "   Then
                        Dim   SendBuff()   As   Byte   =   Encoding.ASCII.GetBytes( "567890 ".ToCharArray())
                        objSocketClient.Sock.Send(SendBuff,   SendBuff.Length,   SocketFlags.None)
                End   If
                objSocketClient.RecieveCallback(Me)


        End   Sub
End   Class

Public   Class   SocketClient
        Private   m_sock   As   Socket
        Private   RecvBuff(256)   As   Byte

        Public   Sub   New(ByVal   sckSock   As   Socket)
                m_sock   =   sckSock
        End   Sub

        Public   ReadOnly   Property   Sock()   As   Socket
                Get
                        Return   m_sock
                End   Get
        End   Property

        Public   Sub   RecieveCallback(ByVal   objSocketServer   As   SocketServer)
                Dim   RecieveData   As   AsyncCallback
                Try
                        RecieveData   =   New   AsyncCallback(AddressOf   objSocketServer.OnRecieveData)
                        m_sock.BeginReceive(RecvBuff,   0,   RecvBuff.Length,   SocketFlags.None,   RecieveData,   Me)
                Catch   ex   As   Exception

                End   Try
        End   Sub

        Public   Function   GetRecieveData(ByVal   ar   As   IAsyncResult)   As   Byte()
                Dim   intByteLen   As   Integer
                Dim   bytReturn   As   Byte()

                intByteLen   =   0
                Try
                        intByteLen   =   m_sock.EndReceive(ar)
                Catch   ex   As   Exception

                End   Try
                ReDim   bytReturn(intByteLen   -   1)
                Array.Copy(RecvBuff,   bytReturn,   intByteLen)
                Return   bytReturn
        End   Function
End   Class
问题:
点击btnStart运行之后,客户端服务端连接及发送接收数据一切正常
但在点击btnStop按钮之后,跟踪发现
        Public   Sub   StopRun()
                RunState   =   False
                sckServer.Close()
        End   Sub
也成功执行完毕,原以为应该服务端就停了,可异步方式的托管代码,却还是执行了
        Private   Sub   OnConnectRequest(ByVal   ar   As   IAsyncResult)
                Done.Set()


                Dim   Listener   As   Socket   =   CType(ar.AsyncState,   Socket)
                NewConnection(Listener.EndAccept(ar))
                Listener.BeginAccept(New   AsyncCallback(AddressOf   OnConnectRequest),   Listener)
        End   Sub
并在
NewConnection(Listener.EndAccept(ar))
报错
具体错误是指因sckServer.Close()而导致传进来的ar值因对象已释放而无法访问

请高手帮忙解决,谢谢!

[解决办法]
mark..学习!!
[解决办法]
这是正常的,你要在这里作异常处理。当Socket被关闭后,BeginAccept、BeginReceive、BeginSend、Accept、Receive、Send都会立即返回。并引发异常!所以你要在这些地方作异常处理!
[解决办法]
我的给你参考一下,删除了很多内部的东西,可能运行不了,只能看看,呵呵

New了以后直接BeginReceive就可以了。
关闭时只要Close就行了。

代码如下:

Imports System.IO
Imports System.Text
Imports System.Net
Imports System.Net.Sockets

Public Class MSComm
Implements IDisposable

#Region " 变量定义 "
'-------------------------------
Private _LocalIp As String '侦听本机IP
Private _LocalPort As Integer '侦听本机端口
Private _bKeepWorking As Boolean = False '是否继续侦听和异步接收数据的标志
'***********************************
Private sckListener As TcpListener '连接侦听器
Private sckServer As Socket '服务器连接(被连接方)
'-------------------------------

Private _ReceiveString As String = String.Empty
Private _ReceiveTimeout As Integer = 10
Private _ErrMessage As String = String.Empty
#End Region

#Region " Dispose "
Private Sub Dispose() Implements IDisposable.Dispose
_bKeepWorking = Nothing
_LocalIp = Nothing
_LocalPort = Nothing
_ReceiveString = Nothing
_ReceiveTimeout = Nothing
_ErrMessage = Nothing
MyBase.Finalize()
End Sub
#End Region

#Region " 属性定义 "
Public ReadOnly Property RemoteIP() As String
Get
Try
Return CType(sckServer.RemoteEndPoint, IPEndPoint).Address.ToString
Catch
Return " "
End Try
End Get
End Property

Public ReadOnly Property ErrMessage() As String
Get
Return _ErrMessage
End Get
End Property

Public Property ReceiveTimeout() As Integer
Get
Return _ReceiveTimeout
End Get
Set(ByVal Value As Integer)
_ReceiveTimeout = Value
End Set
End Property

#End Region

#Region " New "
Public Sub New(ByVal ListenIP As String, ByVal ListenPort As Integer)
_LocalIp = ListenIP
_LocalPort = ListenPort

'开始侦听连接
StartListen()
End Sub
#End Region

#Region " 事件:ConnectionEvent "
Delegate Sub NotificationCallback(ByVal notify As sockNotificationEnum, ByVal sckClient As MSComm, ByVal SourceData As Object, ByVal sockHead As MSDefine.SockHead, ByVal sockBody As Object) ', ByVal sockPrefix As MSDefine.SockPrefix)
Public Event ConnectionEvent As NotificationCallback
#End Region

Private Sub StartListen()


ShutDownListener()
Try
sckListener = New TcpListener(IPAddress.Parse(_LocalIp), _LocalPort)

Dim thdLsn As New Threading.Thread(AddressOf StartListenBase)
thdLsn.Name = "侦听线程 "
thdLsn.Start()
Catch ex As Exception
ShutDownListener()
End Try
End Sub

Private Sub StartListenBase()
sckListener.Start()
Try
Do
Dim sckTmp As Socket = sckListener.AcceptSocket

ShutDownServer()

sckServer = sckTmp
sckTmp = Nothing

BeginReceive()
Loop Until _bKeepWorking = False
Catch e As Exception
If _bKeepWorking Then
ShutDownListener()
StartListen()
Else
ShutDownListener()
End If
End Try
End Sub

#Region " Close "
Public Overloads Sub Close()
EndReceive()

ShutDownListener()
ShutDownServer()

Dispose()
End Sub

Private Sub ShutDownListener()
If Not IsNothing(sckListener) Then
sckListener.Stop()
sckListener = Nothing
End If
End Sub

Private Sub ShutDownServer()
If Not (sckServer Is Nothing) Then
Try
sckServer.Shutdown(SocketShutdown.Both)
Catch
Finally
sckServer.Close()
sckServer = Nothing
End Try
_ServerState = ConnectionStateEnum.Closed
End If
End Sub
#End Region

#Region " EstablishSocket "
Private Sub EstablishSocket(ByVal state As Object)
Try
If Not IsNothing(sckServer) Then
ReceiveAsync()
If _bKeepWorking Then
_ErrMessage = String.Empty
RaiseEvents(sockNotificationEnum.RemoteClose, Nothing, Nothing, Nothing)
End If
Else
ShutDownServer()
_ErrMessage = String.Empty
RaiseEvents(sockNotificationEnum.ConnectionError, Nothing, Nothing, Nothing)
End If
Catch e As IOException
Dim sockExp As SocketException = CType(e.InnerException, SocketException)
If Not (sockExp Is Nothing) And sockExp.ErrorCode = 10054 Then
_ErrMessage = String.Empty
RaiseEvents(sockNotificationEnum.RemoteClose, Nothing, Nothing, Nothing)
Else
_ErrMessage = sockExp.Message
RaiseEvents(sockNotificationEnum.ConnectionError, Nothing, Nothing, Nothing)
ShutDownServer()
End If
sockExp = Nothing
Catch e As Exception
_ErrMessage = e.Message
RaiseEvents(sockNotificationEnum.ConnectionError, Nothing, Nothing, Nothing)
ShutDownServer()
End Try
End Sub
#End Region

#Region " BeginReceive,EndReceive "
Private Sub BeginReceive()
_bKeepWorking = True
System.Threading.ThreadPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf EstablishSocket))
End Sub

Private Sub EndReceive()
_bKeepWorking = False
End Sub

Private Sub ReceiveAsync()
Dim _bufferRead(CCommunicationBufferSize - 1) As Byte
Dim _RcvBytes As Integer = 0
Dim readStream As New NetworkStream(sckServer)
Dim strSocket As String = " "


Dim intEnd As Integer = 0

sckServer.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0)
Do While _bKeepWorking
_bufferRead.Clear(_bufferRead, 0, CCommunicationBufferSize - 1)
_RcvBytes = readStream.Read(_bufferRead, 0, CCommunicationBufferSize)
If _RcvBytes > 0 Then

End If
Loop

intEnd = Nothing
_bufferRead = Nothing
_RcvBytes = Nothing
strSocket = Nothing
readStream = Nothing
End Sub

Private Overloads Sub RaiseEvents(ByVal EventType As sockNotificationEnum, ByVal tHead As MSDefine.SockHead, ByVal tBody As Object, ByVal tPrefix As MSDefine.SockPrefix)
RaiseEvent ConnectionEvent(EventType, Me, " ", tHead, tBody)
End Sub

Private Overloads Sub RaiseEvents(ByVal EventType As sockNotificationEnum, ByVal SourceData As String)
RaiseEvent ConnectionEvent(EventType, Me, SourceData, Nothing, Nothing)
End Sub

Private Sub ThrowMsg(ByVal strMsg As String)
RaiseEvent ConnectionEvent(sockNotificationEnum.ShowMsg, Me, "[MidSocket] " & strMsg, Nothing, Nothing)
End Sub

#End Region
End Class

[解决办法]
你给你的socket设置一个状态标记
你在调用委托之前判断一下socket的状态,就可以避免

热点排行