UDP SocketException - 每个套接字地址通常只允许使用一次 [英] UDP SocketException - Only one usage of each socket address is normally permitted

查看:13
本文介绍了UDP SocketException - 每个套接字地址通常只允许使用一次的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尽管这里有很多非常相似的问题,但提供的答案都没有帮助我,这让我很伤心:(

As much as there are many questions on here that are very similar, none of the supplied answers have helped me, which makes me sad :(

我有一个非常大的管理系统,我的任务是编写一些 UDP 数据包发送/接收.我已经编写了一个原型并且一切都很好,所以我开始将我的代码合并到所述系统中.但是,我现在弹出了一个(不是停止显示,而是烦人的)SocketException:

I've got a very large management system that I've been tasked to write some UDP packet sending/receiving for. I'd already written a prototype and all was well, so I started merging my code into said system. However, I've now got a (not show-stopping, but annoying) SocketException popping up:

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:WORKTrunkGooseOrdersClassesSheetCounterDeviceServerUDPReceiver.vb:line 39

这里是 UDPReceiver 类 - 它负责只是坐在一个循环中并等待来自我们在这个地方点缀的设备服务器的响应.

Here is the UDPReceiver class - Which is responsible for just sitting in a loop and waiting for responses from the Device Servers we've got dotted about the place.

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().但是,当有人想重新启动它时,在 SitAndReceive 过程中的 byData = _ReceivingClient.Receive(epEndPoint) 行发生上述异常.

Now, all I'm doing in the main form, is: When my listener form is closed - I want to close the listener down (obviously)... For this, I'm using Dispose(). However, when someone wants to start it up again, said exception occurs on the byData = _ReceivingClient.Receive(epEndPoint) line in the SitAndReceive procedure.

由于 UDP 是基于事务的,并且它的套接字(理论上可能)不能处于 CLOSE_WAIT 状态,是什么阻止我关闭它然后立即重新启动侦听器?

Since UDP is transaction based and its sockets (possibly theoretically) can't be in a CLOSE_WAIT state, what is stopping me from closing it down and then immediately relaunching the listener?

我必须承认我是 UDP 套接字的新手,但到目前为止,我发现使用它们很有趣,即使这个异常不会导致最终用户软件崩溃(使用简单的 try/catch),它确实让我很感兴趣,我想了解它为什么会发生.

I must admit I'm new to UDP sockets, so far however, I've found them a joy to work with and even though this exception wouldn't crash an end-users software (with a simple try/catch), it does have me intrigued and I'd like to understand why it's happening.

非常感谢任何帮助.

推荐答案

最终设法解决了这个问题.显然,如果您想与一个套接字建立多个连接,则必须手动配置它,如下所示:

Managed to figure this out in the end. Apparently if you want to have more than one connection to a socket, you have to manually configure it, like 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)

现在工作,所以我很高兴.

Works now, so I'm happy.

这篇关于UDP SocketException - 每个套接字地址通常只允许使用一次的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆