Public Class UDPCommon
Implements IDisposable
'The UDP listening components.
Private WithEvents locUDP As System.Net.Sockets.Socket
Private WithEvents locUDPOut As System.Net.Sockets.UdpClient
Private ThreadListen As Threading.Thread
Private timeCount As Integer
Private broad As System.Net.IPEndPoint
Private whoAmI As Byte
'The dataQueue
Private dgList As Queue(Of DataGramReceiver)
'The result
Private disposedValue As Boolean = False ' To detect redundant calls
'Synchronization.
Private Shared myContext As System.Threading.SynchronizationContext
#Region "Constructors and Destructors"
Public Sub New(ByVal myAdd As Byte, ByVal myPort As Integer)
'Set up the queue.
whoAmI = myAdd
dgList = New Queue(Of DataGramReceiver)
locUDPOut = New Net.Sockets.UdpClient()
locUDPOut.Client.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, True)
locUDP = New Net.Sockets.Socket(Net.Sockets.AddressFamily.InterNetwork, Net.Sockets.SocketType.Dgram, Net.Sockets.ProtocolType.Udp)
locUDP.SetSocketOption(Net.Sockets.SocketOptionLevel.Socket, Net.Sockets.SocketOptionName.ReuseAddress, True)
locUDP.Bind((New Net.IPEndPoint(Net.IPAddress.Any, myPort)))
locUDPOut.EnableBroadcast = True
broad = New System.Net.IPEndPoint(System.Net.IPAddress.Broadcast, myPort)
myContext = System.Threading.SynchronizationContext.Current
'Start listening.
ThreadListen = New Threading.Thread(AddressOf WaitForPending)
ThreadListen.Name = "Listening Thread"
ThreadListen.Start()
End Sub
' IDisposable
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If Not Me.disposedValue Then
If disposing Then
ThreadListen.Abort()
locUDP.Close()
locUDPOut.Close()
End If
' TODO: free shared unmanaged resources
End If
Me.disposedValue = True
End Sub
#Region " IDisposable Support "
' This code added by Visual Basic to correctly implement the disposable pattern.
Public Sub Dispose() Implements IDisposable.Dispose
' Do not change this code. Put cleanup code in Dispose(ByVal disposing As Boolean) above.
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
#End Region
#End Region
#Region "Properties and Events"
Public Event MessageIn()
Public ReadOnly Property MessageCount() As Integer
Get
Return dgList.Count
End Get
End Property
Public ReadOnly Property NextMessage() As DataGramReceiver
Get
Return dgList.Dequeue
End Get
End Property
#End Region
#Region "Public Functions"
'This will get the next DGR from the queue.
Public Function GetNext() As DataGramReceiver
Dim dgRet As New DataGramReceiver
Threading.Monitor.Enter(Me)
Try
If dgList.Count > 0 Then
dgRet = New DataGramReceiver(dgList.Dequeue)
End If
Catch ex As Exception
Windows.Forms.MessageBox.Show(ex.Message, "Error Getting DataGramReceiver", MessageBoxButtons.OK, MessageBoxIcon.Error)
Finally
Threading.Monitor.Exit(Me)
End Try
'It may be the default, or it may not, either way it is a good local copy in the calling thread, return it.
Return dgRet
End Function
'Empties the queue
Public Sub Flush()
Threading.Monitor.Enter(Me)
Try
dgList.Clear()
Finally
Threading.Monitor.Exit(Me)
End Try
End Sub
Public Sub SendMessage(ByVal btArr() As Byte, ByVal toWho As Byte, ByVal what As Byte)
Dim lBtArr(btArr.Length + 2) As Byte
lBtArr(0) = whoAmI
lBtArr(1) = toWho
lBtArr(2) = what
System.Array.Copy(btArr, 0, lBtArr, 3, btArr.Length)
'NOTE: NEED TO CHECK THAT THIS IS DOING AS IT SHOULD.
locUDPOut.Send(lBtArr, lBtArr.Length, broad)
End Sub
#End Region
#Region "Private Functions"
Private Sub WaitForPending()
Try
Dim bHolder(511) As Byte
Dim numIn As Integer
Dim dgRec As DataGramReceiver
Dim bTrans() As Byte
numIn = locUDP.Receive(bHolder, 512, Net.Sockets.SocketFlags.None)
If numIn > 0 Then
If bHolder(0) <> whoAmI AndAlso bHolder(1) = 0 OrElse bHolder(1) = 100 Then
'Set the holder up to the right size.
ReDim bTrans(numIn)
Array.Copy(bHolder, 3, bTrans, 0, numIn - 3)
dgRec = New DataGramReceiver(bHolder(0), bHolder(2), bTrans)
Add(dgRec)
Else
myContext.Post(AddressOf TimedOut, Nothing)
End If
End If
Catch ex As System.Net.Sockets.SocketException
'Not actually doing anything here now.
Catch ex As Exception
'Not doing anything here.
Finally
myContext.Post(AddressOf TimedOut, Nothing)
End Try
End Sub
'Adds one DGR to the queue
Private Sub Add(ByVal dgR As DataGramReceiver)
'Set the monitor.
Threading.Monitor.Enter(Me)
Try
dgList.Enqueue(dgR) 'That's all that happens.
Finally
Threading.Monitor.Exit(Me)
End Try
myContext.Post(AddressOf GotData, Nothing)
End Sub
'This is invoked by the other thread.
Private Sub GotData(ByVal state As Object)
RaiseEvent MessageIn()
End Sub
Private Sub TimedOut(ByVal state As Object)
ThreadListen = New Threading.Thread(AddressOf WaitForPending)
ThreadListen.Start()
End Sub
#End Region
End Class