UDP local broadcast

Abandoned account picture Abandoned account · May 20, 2013 · Viewed 9.3k times · Source

I'm working on a remote control tool. The client runs a program to locally send commands to servers in order to control them.

However, the client doesn't know the server's IP address and vice versa.

I decided to use UDP broadcasting (please tell me if there's a better way to do this, I tried using multicast but I didn't really understand it). When started, the client (which controls the servers) broadcasts a message to tell the servers that a new client connected. Then (or when the server is started), the servers broadcast their own IP addresses. When the client receives an IP address, it tries to connect via TCP.

Unfortunately, I ran into problems with that. I randomly got An existing connection was forcibly closed by the remote host exceptions and I wasn't able to find out why. The exception occurred in my client program when listening for UDP broadcasts.

Now, I'm looking for a better way to find the clients. Should I use broadcast or multicast? How would I implement that?

EDIT: It wouldn't be a problem to use multiple ports. However, I need to be able to run a client AND a server on a single computer.


Here's the code I was using

Client (controls servers)

'Variables
    Private UdpBroadcaster As UdpClient
    Private UdpBroadcasterEndpoint As New IPEndPoint(IPAddress.Broadcast, 4334)


'Sub New()
    Try
        UdpBroadcaster = New UdpClient(4333)
        UdpBroadcaster.EnableBroadcast = True
    Catch
        MsgBox("Error creating UDP client! Port already in use?", ...)
    End Try

'Called when the application starts
Private Sub StartUdpListener()
    Dim ListenerUdp As New Thread(AddressOf UdpListener)
    ListenerUdp.IsBackground = True
    ListenerUdp.Start()
End Sub

'Started as thread in StartUdpListener()
Private Sub UdpListener()
    Try
        Do
            'The next line fails with the error I described (An existing connection was forcibly closed by the remote host)
            Dim ReceivedBytes() As Byte = UdpBroadcaster.Receive(UdpBroadcasterEndpoint)
            Dim ReceivedString As String = System.Text.Encoding.UTF32.GetString(ReceivedBytes)

            'The following three lines will just connect to the received hostname
            Dim ScanThread As New Thread(Sub() ScanSingle(ReceivedString))
            ScanThread.IsBackground = True
            ScanThread.Start()
        Loop
    Catch
        If Not UdpBroadcaster Is Nothing Then
            UdpBroadcaster.Close()
            UdpBroadcaster = Nothing
        End If

        InvokeStatus("UDP connection lost, please try again later.")
    End Try
End Sub

'Called when the application starts and when the user manually clicks the "UDP Scan" button
Private Sub StartBroadcastUdpThread()
    Dim UdpBroadcastThread As New Thread(Sub() BroadcastUdp())
    UdpBroadcastThread.IsBackground = True
    UdpBroadcastThread.Start()
End Sub

'Started as thread in StartBroadcastUdpThread()
Private Sub BroadcastUdp()
    If UdpBroadcaster Is Nothing Then
        Try
            UdpBroadcaster = New UdpClient(4333)
            UdpBroadcaster.EnableBroadcast = True
        Catch
            MsgBox("Error creating UDP Client.", MsgBoxStyle.Critical, "Error")
            Application.Exit()
            Return
        End Try
    End If

    Dim BroadcastBytes() As Byte = System.Text.Encoding.UTF32.GetBytes("Client-Identify")
    UdpBroadcaster.Send(BroadcastBytes, BroadcastBytes.Length, UdpBroadcasterEndpoint)
    InvokeStatus("UDP request sent successfully")
End Sub



Servers (controlled by client)

'Variables
Private UdpBroadcaster As UdpClient
Private UdpBroadcasterEndpoint As New IPEndPoint(IPAddress.Broadcast, 4333)

'Main method
Public Sub Main()
    Try
        UdpBroadcaster = New UdpClient(4334)
        UdpBroadcaster.EnableBroadcast = True

        StartUdpListener()
        StartBroadcastUdpThread()
    Catch
        Console.WriteLine("Failed to create server. Port already in use?")
    End Try
End Sub

'Called in Main()
Private Sub StartUdpListener()
    Dim ListenerUdp As New Thread(AddressOf UdpListener)
    ListenerUdp.IsBackground = True
    ListenerUdp.Start()
End Sub

'Started as thread in StartUdpListener()
Private Sub UdpListener()
    Try
        Do
            Dim ReceivedBytes() As Byte = UdpBroadcaster.Receive(UdpBroadcasterEndpoint)
            Dim ReceivedString As String = System.Text.Encoding.UTF32.GetString(ReceivedBytes)

            If ReceivedString.Equals("Client-Identify") Then
                StartBroadcastUdpThread()
            End If
        Loop
    Catch
        If Not UdpBroadcaster Is Nothing Then
            UdpBroadcaster.Close()
        End If
    End Try
End Sub

'Called when the application is started or a "Client-Identify" command is received
Private Sub StartBroadcastUdpThread()
    Dim UdpBroadcastThread As New Thread(Sub() BroadcastUdp())
    UdpBroadcastThread.IsBackground = True
    UdpBroadcastThread.Start()
End Sub

'Started as thread in StartBroadcastUdpThread()
Private Sub BroadcastUdp()
    Dim BroadcastBytes() As Byte = System.Text.Encoding.UTF32.GetBytes(Dns.GetHostName)
    UdpBroadcaster.Send(BroadcastBytes, BroadcastBytes.Length, UdpBroadcasterEndpoint)
End Sub

Thanks in advance!

Answer

Abandoned account picture Abandoned account · May 21, 2013

Thank you for your answers. I fixed it by removing the feature to manually call StartBroadcastUdpThread() in my client.

I still don't understand why this happens though. I use exactly the same code for both client and server, except the ports are swapped. The TCP server doesn't crash even if the StartBroadcastUdpThread() method is called multiple times, the client does. By the way, the problem occurs regardless of whether the client or server is started first.

Even if I don't really understand why broadcasting the second time stops the client from receiving broadcasts - it's fixed for now. Thanks for you help!