5

ここには非常によく似た質問がたくさんありますが、提供された回答はどれも役に立たず、悲しくなります:(

私は非常に大規模な管理システムを持っており、UDP パケットの送信/受信を作成する任務を負っています。私はすでにプロトタイプを作成しており、すべてが順調だったので、コードをそのシステムにマージし始めました。ただし、(ショーを停止するのではなく、迷惑な)SocketExceptionがポップアップするようになりました。

System.Net.Sockets.SocketException occurred
  ErrorCode=10048
  Message=Only one usage of each socket address (protocol/network address/port) is normally permitted
  NativeErrorCode=10048
  Source=System
  StackTrace:
       at System.Net.Sockets.Socket.DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress)
       at System.Net.Sockets.Socket.Bind(EndPoint localEP)
       at System.Net.Sockets.UdpClient..ctor(Int32 port, AddressFamily family)
       at System.Net.Sockets.UdpClient..ctor(Int32 port)
       at Goose.Job.DeviceServerUDPReceiver.InitialiseReceiverClient() in C:\WORK\Trunk\GooseOrders\Classes\SheetCounter\DeviceServerUDPReceiver.vb:line 39

これが UDPReceiver クラスです。これは、ループに座って、その場所に点在するデバイス サーバーからの応答を待機する役割を果たします。

Public Class DeviceServerUDPReceiver : Implements IDisposable
'///////////////////////////////////////////////////////////////////////////////
' CONSTANTS
'///////////////////////////////////////////////////////////////////////////////
Private Const TIBBO_DEVICE_REPLY_CMD_START As Integer = 0
Private Const TIBBO_DEVICE_REPLY_CMD_END As Integer = 3
Private Const TIBBO_MESSAGE_REPLY_DIVIDER As String = "_"
Private Const TIBBO_DEVICE_REPLY_OK As String = "OK"

'///////////////////////////////////////////////////////////////////////////////
' MEMBER VARIABLES
'///////////////////////////////////////////////////////////////////////////////
Public _ReceivingClient As System.Net.Sockets.UdpClient
Public _iReceivingPort As Integer = 2002
Public _thReceivingThread As System.Threading.Thread
Public _bClosing As Boolean

'///////////////////////////////////////////////////////////////////////////////
' EVENTS
'///////////////////////////////////////////////////////////////////////////////
Public Event GotDeviceResponse(ByVal sResponse As String)
Public Event FoundNewDevice(ByVal TibboObject As TibboDevice)

'///////////////////////////////////////////////////////////////////////////////
' METHODS
'///////////////////////////////////////////////////////////////////////////////
' Initialises the UDP receiver client on the specified port number. Then runs
' a listening thread constantly waiting to receive udp messages
Public Sub InitialiseReceiverClient()
    Try
        ' TODO - FIX SOCKET EXCEPTION HERE - NOT THREAD ISSUE - THIS IS DUE TO 
        ' THE SOCKET NOT BEING CLOSED. BUT SEEING HOW UDP IS CONNECTIONLESS .... ?!
        _ReceivingClient = New System.Net.Sockets.UdpClient(_iReceivingPort)
        Dim thStartThread As Threading.ThreadStart = New Threading.ThreadStart(AddressOf SitAndReceive)
        _thReceivingThread = New Threading.Thread(thStartThread)
        _thReceivingThread.IsBackground = True
        _thReceivingThread.Start()
    Catch ex As System.Net.Sockets.SocketException
        Console.WriteLine("Socket Exception: " & ex.Message)
    Finally

    End Try
End Sub

' The endless loop listener thread. Will sit and wait for udp packets to 
' process
Private Sub SitAndReceive()
    Dim epEndPoint As System.Net.IPEndPoint = New System.Net.IPEndPoint(System.Net.IPAddress.Any, _iReceivingPort)

    ' infinite loop to listen for udp messages
    While (_bClosing = False)
        Try
            Dim sMessage As String = ""
            Dim byData() As Byte

            byData = _ReceivingClient.Receive(epEndPoint)
            sMessage = System.Text.Encoding.ASCII.GetString(byData)
            Console.WriteLine(sMessage)

            ProcessIncomingUDPDataMessage(sMessage)

        Catch ex As System.Net.Sockets.SocketException
            Console.WriteLine(ex.Message)
        End Try
    End While
End Sub

' close the connection to the receiving udp socket
Public Sub Close()
    _bClosing = True
End Sub


' Processes incoming udp packets for answeres from the device servers
Private Sub ProcessIncomingUDPDataMessage(ByVal sMessage As String)

    ' UDP Data packet from Tibbo devices is set out as follows
    '
    ' CMD_ANSWER
    ' Where "CMD" = The command the device is replying too and
    ' "ANSWER" = It's reply
    Select Case sMessage.Substring(TIBBO_DEVICE_REPLY_CMD_START, TIBBO_DEVICE_REPLY_CMD_END)
        Case TibboDevice.DEVICE_COMMAND_ATO
            '/////////////////////////////////////////////////////////////////////////
            ' Any Tibbo's out there reply message 
            '/////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sMacAddress As String = s(2) ' the replying devices' mac address
            Dim sIpAddress As System.Net.IPAddress = System.Net.IPAddress.Parse(s(3)) ' ip
            Dim sNetBiosName As String = s(1) ' netbios name
            Dim iTibboStatus As TibboDevice.ETIIBO_DEVICE_STATE = TibboDevice.ETIIBO_DEVICE_STATE.TIBBO_DEVICE_STATE_BAD ' status

            ' set this device status depending on the reply
            If s(4) = TIBBO_DEVICE_REPLY_OK Then
                iTibboStatus = TibboDevice.ETIIBO_DEVICE_STATE.TIBBO_DEVICE_STATE_OK
            End If

            ' create a new tibbo device to pass back to the main form
            Dim Tibbo As TibboDevice = New TibboDevice(sMacAddress, sIpAddress, sNetBiosName, iTibboStatus)
            ' raise event to add this to our list
            RaiseEvent FoundNewDevice(Tibbo)


        Case TibboDevice.DEVICE_COMMAND_STS
            '//////////////////////////////////////////////////////////////////////////
            ' Status reply message
            '//////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            ' format our string nicely
            sResult &= "Mac Address: " & vbTab & vbTab & s(1)
            sResult &= Environment.NewLine & "IP Address: " & vbTab & vbTab & s(2)
            sResult &= Environment.NewLine & "Device Name: " & vbTab & vbTab & s(3)
            sResult &= Environment.NewLine & "TiOS FW: " & vbTab & vbTab & s(4)
            sResult &= Environment.NewLine & "Goose SC FW: " & vbTab & vbTab & s(5)
            sResult &= Environment.NewLine & "System Uptime: " & vbTab & vbTab & s(6)
            sResult &= Environment.NewLine & "System Time: " & vbTab & vbTab & s(7)
            sResult &= Environment.NewLine & "System Status: " & vbTab & vbTab & s(8)

            RaiseEvent GotDeviceResponse(sResult)

        Case TibboDevice.DEVICE_COMMAND_ASC
            '////////////////////////////////////////////////////////////////////////////
            ' Average sheet count message
            '////////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            RaiseEvent GotDeviceResponse(sResult)

        Case TibboDevice.DEVICE_COMMAND_NAM
            '////////////////////////////////////////////////////////////////////////////
            ' Changed device name reply message
            ' Device will reply NAM_[NEWNAME] - once it's set it's new name
            '////////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            RaiseEvent GotDeviceResponse(sResult)

        Case TibboDevice.DEVICE_COMMAND_IDX
            '////////////////////////////////////////////////////////////////////////////
            ' Device responds with it's device id
            '////////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            ' TODO - do something with the result

        Case TibboDevice.DEVICE_COMMAND_RBT
            '////////////////////////////////////////////////////////////////////////////
            ' Device is going down for a reboot - not much to do here, we have to wait
            '////////////////////////////////////////////////////////////////////////////

        Case TibboDevice.DEVICE_COMMAND_BUZ
            '////////////////////////////////////////////////////////////////////////////
            ' Device has played it's buzz sound - ignore
            '////////////////////////////////////////////////////////////////////////////

        Case TibboDevice.DEVICE_COMMAND_FSH
            '////////////////////////////////////////////////////////////////////////////
            ' Device flashed it's LEDs - ignore
            '////////////////////////////////////////////////////////////////////////////

        Case TibboDevice.DEVICE_COMMAND_AIP
            '////////////////////////////////////////////////////////////////////////////
            ' Device replies with it's actual ip address
            '////////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            ' TODO - do something with the result

        Case TibboDevice.DEVICE_COMMAND_CBC
            '////////////////////////////////////////////////////////////////////////////
            ' Device replies with it's current box count
            '////////////////////////////////////////////////////////////////////////////
            Dim s() As String = sMessage.Split(TIBBO_MESSAGE_REPLY_DIVIDER)
            Dim sResult As String = ""

            ' TODO - do something with the result

        Case TibboDevice.DEVICE_COMMAND_STP
            '////////////////////////////////////////////////////////////////////////////
            ' Device has been stopped - won't reply. Only way to bring it back to life
            ' is to press the 'reset' button on the actual unit - ignore
            '////////////////////////////////////////////////////////////////////////////
    End Select

End Sub

Protected Overridable Overloads Sub Dispose(disposing As Boolean)
    If (disposing) Then
        ' free managed objects
        '_ReceivingClient = Nothing
        _bClosing = True
    End If
End Sub

Public Overloads Sub Dispose() Implements IDisposable.Dispose
    Dispose(True)
    GC.SuppressFinalize(Me)
End Sub


End Class

Dispose()現在、メイン フォームで行っていることは次のとおりです。リスナー フォームが閉じているとき - リスナーを閉じたい (明らかに)... ただし、誰かがそれを再起動したい場合、手順のbyData = _ReceivingClient.Receive(epEndPoint)行で例外が発生します。SitAndReceive

UDP はトランザクション ベースであり、そのソケットは (おそらく理論的には) CLOSE_WAIT 状態にすることができないため、それを閉じてすぐにリスナーを再起動するのを妨げているのは何ですか?

私は UDP ソケットに慣れていないことを認めなければなりませんが、これまでのところ、それらを扱うのが楽しいと感じており、この例外がエンドユーザーのソフトウェアを (単純な試行/キャッチで) クラッシュさせることはありませんが、実際にクラッシュします。興味をそそられ、なぜそれが起こっているのかを理解したい.

どんな助けでも大歓迎です。

4

1 に答える 1