2013-07-22 8 views
5

So viel wie es viele Fragen hier, die sehr ähnlich sind, keine der gelieferten Antworten haben mir geholfen, das macht mich traurig :(UDP Socket - Nur eine Verwendung einzeln Socketadresse normalerweise erlaubt ist

I Ich habe ein sehr großes Verwaltungssystem, das ich beauftragt habe, ein paar UDP-Pakete zu schreiben/zu empfangen. Ich hatte bereits einen Prototyp geschrieben und alles war gut, also habe ich angefangen, meinen Code in das System zu integrieren. ve bekam jetzt ein (nicht show-stopping, aber ärgerlich) Socket Aufspringen:

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 

Hier ist die UDPReceiver Klasse - die in verantwortlich ist für nur sitzen eine Schleife und warten auf Antworten von den Device Servern, die wir über den Ort verteilt haben.

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 

Nun, alles, was ich in der Hauptform zu tun, ist: Wenn meine Zuhörer Form geschlossen ist - Ich mag die Zuhörer schließen (natürlich) ... Dazu verwende ich Dispose(). Wenn jedoch jemand es erneut starten möchte, tritt diese Ausnahme auf der byData = _ReceivingClient.Receive(epEndPoint) Zeile in der SitAndReceive Prozedur auf.

Da UDP transaktionsbasiert ist und seine Sockets (möglicherweise theoretisch) nicht in einem CLOSE_WAIT-Zustand sein können, was hindert mich daran, es zu schließen und dann sofort den Hörer neu zu starten?

Ich muss zugeben, ich bin neu in UDP-Sockets, aber bisher habe ich festgestellt, dass sie eine Freude zu arbeiten und obwohl diese Ausnahme nicht eine Endbenutzer-Software zum Absturz bringen würde (mit einem einfachen Versuch/fangen), es hat mich intrigiert und ich würde gerne verstehen, warum es passiert.

Jede Hilfe wird sehr geschätzt.

Antwort

14

verwaltet, um dies herauszufinden, am Ende. Offenbar, wenn Sie mehr als einen Anschluss an eine Steckdose haben wollen, müssen Sie es manuell konfigurieren, etwa so:

Dim endPoint = New System.Net.IPEndPoint(0, _iReceivingPort) 
_ReceivingClient = New System.Net.Sockets.UdpClient() 
_ReceivingClient.ExclusiveAddressUse = False 
_ReceivingClient.Client.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, True) 
_ReceivingClient.Client.Bind(endPoint) 

jetzt funktioniert, also bin ich glücklich.

+1

Schön! Ich hatte das gleiche Problem. Ich brauchte eine Weile, um herauszufinden, warum es nicht funktionierte und ich erkannte, dass ich mein UdpClient-Objekt mit einem Port (wie '_receiver = neuer UdpClient (myPort)') instanziiert, der eine darunter liegende Bindung eingehen muss. Nachdem ich den Standardkonstruktor verwendet habe, hat es gut funktioniert. – Daniel

+0

Nice one :) Ich bin froh, dass es funktioniert hat! – LokiSinclair

+0

Ihre Lösung funktioniert gut! Ich habe eine Multicast-Anfrage mit mehreren Empfängern auf demselben Host gesendet. Ich bekam den gleichen Fehler, als ich versuchte, mehr als einen Empfänger zu betreiben, der denselben Port hören musste. –

Verwandte Themen