Thread: Upd
View Single Post
 
Old 08-06-2014, 11:00 AM
passel's Avatar
passel passel is offline
Sinecure Expert

Super Moderator
* Guru *
 
Join Date: Jun 2003
Location: Upstate New York, usa
Posts: 8,024
Default

No clue really. I've only looked at the async callback method briefly and never tried it out yet.
I've used the UDPClient 99% of the time, and haven't had any issue over the years, but you may have a reason for not using it.

My preference is to just start a background thread to do the receiving in, leaving the GUI free to send and react to user input.

I put together a simple example for someone awhile back, where he wanted to send some integer data and a string between two processes.
So the example had a sending side and a receiving side, and I used mouse input on the sending side to get X,Y values, and drew lines on the receiving side.
He later wanted to send data the other direction so I just said do the same thing in the other direction. I copied the code from the sender to the receiver, so now they are really pretty much the same, just port numbers reversed between sending and receiving.
I'll post those two, so you can check them out if curious.

I exceeded the 10,000 character limit, so since both sides are the same except for the port swap, I'll just post the one code and you can copy it into two projects, just swap the final 0 and 1 digit of the port numbers on one of the projects.
(port numbers swapped example)
Code:
  Dim udpSender As New UdpClient(32221)                               'Listen on UDP port 32221
  Dim destIPnt As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 32220) 'Send to UDP port 32220
Code:
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets

Public Class Form1
  Dim udpSender As New UdpClient(32220)                               'Listen on UDP port 32220
  Dim destIPnt As New IPEndPoint(IPAddress.Parse("127.0.0.1"), 32221) 'Send to UDP port 32221

  Dim drawMap As New Bitmap(1200, 1000)
  Dim gMap As Graphics
  Dim receiveThread As New Thread(AddressOf Receiver)
  Dim leaving As Boolean

  Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    If e.Button = Windows.Forms.MouseButtons.Left Then
      Dim s As String = "ThisAtest"
      Dim sl As Integer = s.Length
      Dim b(11 + s.Length) As Byte '11 for X,Y and string size, + length of the string
      Buffer.BlockCopy(BitConverter.GetBytes(e.X), 0, b, 0, 4) 'convert X to 4 byte array and copy to b(0..3)
      Buffer.BlockCopy(BitConverter.GetBytes(e.Y), 0, b, 4, 4) 'convert Y to 4 byte array and copy to b(4..7)
      Buffer.BlockCopy(BitConverter.GetBytes(sl), 0, b, 8, 4) 'convert string length to 4 byte array and copy to b(8..11)
      Buffer.BlockCopy(System.Text.Encoding.ASCII.GetBytes(s), 0, b, 12, s.Length)
      udpSender.Send(b, b.Length, destIPnt)
    End If
  End Sub

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim b() As Byte = {0, 0, 0, 0, 0, 0, 0, 0}

    Me.Text = "Drag on this form to draw on the receiving form"
    Me.DoubleBuffered = True
    Me.BackgroundImage = drawMap
    gMap = Graphics.FromImage(drawMap)
    receiveThread.IsBackground = True
    receiveThread.Start()
  End Sub

  Private Sub Receiver()
    Dim remoteIP As New IPEndPoint(IPAddress.Any, 0)  'will hold who sent the data (not utilized)
    Dim b() As Byte 'buffer to receive data
    Dim s As String
    Dim sl As Integer

    Static LastPoint As Point

    Do Until leaving
      b = udpSender.Receive(remoteIP)
      If b.Count > 12 Then 'expect 12 bytes plus string data
        Dim newPoint As Point
        newPoint.X = BitConverter.ToInt32(b, 0)  'convert first 4 bytes (0..3) to Int32 
        newPoint.Y = BitConverter.ToInt32(b, 4)  'convert second 4 bytes (4..7) to Int32
        sl = BitConverter.ToInt32(b, 8)  'get string length
        s = System.Text.ASCIIEncoding.ASCII.GetString(b, 12, sl) 'get ASCII bytes and convert to a string
        Me.Invoke(Sub() Me.Text = s)  'show the string received on the Form's title bar
        gMap.DrawLine(Pens.Black, LastPoint, newPoint)
        LastPoint = newPoint
        Me.BeginInvoke(Sub() Me.Invalidate()) 'Have to use Invoke to do stuff on the GUI thread
      End If
    Loop

  End Sub
End Class
Another more recent experiment had to do with many applications connecting to one, i.e. a multi-client to a server type scenario.
Usually on the server, a socket is used to listen, and when data is received, another socket is created to start communicating with the client that transmitted, so you would have create a socket for every client that connected. In my case, that would be a background thread for each receiver for each socket, etc...
Rather than go that route, since the RemoteIP and Port is available with packet received, I thought I test using just the one socket to receive all packets from all clients, and track the client by RemoteIP and Port.

Now, this is a recent test, only done this week, so is in its first stage, so doesn't clean up after itself, and you need to shutdown the clients first because they don't have an exception handler, but the test worked.
I kicked of six clients and had them run all night and no packets were lost (over 200000 transfers each). Yesterday I opened 20 clients (reduced the window size so only two of the labels were showing so could be packed in a corner of the monitor, running in the background and let run all day). Haven't used two machines with it yet, and the messages are only 8 bytes and only transmitted at about 10hz, so not much of a test at the moment, since even with 20 clients, you're only talking 200 messages in each direction per second, so 400*8 = 3200 bytes worth of data bandwidth per second, which is nothing.

The server has no GUI controls, and neither server or client is a lot of code, but I'll post the code for Server, and attach a zip of the client project since it does have some GUI elements (a button to stop or start the timer which sends data to the server) and some labels, two of which are used. The first label displays a count of each transmit done to the server. The second label displays the count from the server of how many receives it has processed for this particular client. The numbers should match, unless a transfer from client to server is lost. (a lost transfer from server to client won't show because we're not tracking that. The second pair of labels could be used, and and a second counter for the server to increment each transfer could be added if we wanted to track that).
Server Code:
Code:
Imports System.Threading
Imports System.Net
Imports System.Net.Sockets

Public Class Form1

  Private Structure RemoteVehicleConnection
    Public IPandPort As IPEndPoint
    Public HeartBeatCount As Integer
    Public HeartBeatInpCount As Integer
    Public ID As String
  End Structure

  Dim rv As RemoteVehicleConnection
  Dim VehicleList As New List(Of RemoteVehicleConnection)

  Dim socketIn As New UdpClient(12321)                                'Listen on UDP port 12321
  Dim receiveThread As New Thread(AddressOf Receiver)
  Dim leaving As Boolean

  Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    receiveThread.IsBackground = True
    receiveThread.Start()
    Timer1.Enabled = True
  End Sub

  Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    leaving = True
  End Sub

  Private Sub Receiver()
    Dim remoteIP As New IPEndPoint(IPAddress.Any, 0)  'will hold who sent the data 
    Dim b() As Byte 'buffer to receive data
    Dim rvc As RemoteVehicleConnection

    Dim found As Boolean

    Do Until leaving
      remoteIP = New IPEndPoint(IPAddress.Any, 0)
      Try
        b = socketIn.Receive(remoteIP)
        found = False
        Monitor.Enter(VehicleList) 'get exclusive access to the list
        For i As Integer = 0 To VehicleList.Count - 1
          With VehicleList(i)
            If .IPandPort.Port = remoteIP.Port Then
              If .IPandPort.Address.ToString = remoteIP.Address.ToString Then
                found = True
                rvc = VehicleList(i)
                rvc.HeartBeatCount += 1
                rvc.HeartBeatInpCount = BitConverter.ToInt32(b, 0)
                VehicleList(i) = rvc
                Exit For
              End If
            End If
          End With
        Next
        If Not found Then
          rv.IPandPort = remoteIP
          rv.HeartBeatCount = 1
          rv.HeartBeatInpCount = BitConverter.ToInt32(b, 0)
          VehicleList.Add(rv)
          Debug.Print(rv.IPandPort.Port.ToString)
        End If
        Monitor.Exit(VehicleList)
      Catch
      End Try
    Loop

  End Sub

  Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick

    Monitor.Enter(VehicleList) 'get exclusive access to the list
    Dim b(7) As Byte
    For i As Integer = 0 To VehicleList.Count - 1
      With VehicleList(i)
        Buffer.BlockCopy(BitConverter.GetBytes(.HeartBeatCount), 0, b, 0, 4)
        socketIn.Send(b, b.Length, .IPandPort)
      End With
    Next
    Monitor.Exit(VehicleList)
  End Sub
End Class
Client project attached.
Attached Files
File Type: zip UDP_MultiClientTest.zip (17.5 KB, 1 views)
__________________
There Is An Island Of Opportunity In The Middle of Every Difficulty.
Miss That, Though, And You're Pretty Much Doomed.

Last edited by passel; 08-06-2014 at 11:12 AM.
Reply With Quote