3

我正在开发一个远程控制工具。客户端运行一个程序在本地向服务器发送命令以控制它们。

但是,客户端不知道服务器的 IP 地址,反之亦然。

我决定使用 UDP 广播(请告诉我是否有更好的方法来做到这一点,我尝试使用多播但我并不真正理解它)。启动时,客户端(控制服务器)会广播一条消息,告诉服务器有新客户端连接。然后(或在服务器启动时),服务器广播它们自己的 IP 地址。当客户端收到 IP 地址时,它会尝试通过 TCP 连接。

不幸的是,我遇到了问题。我随机遇到An existing connection was forcibly closed by the remote host异常,但无法找出原因。侦听 UDP 广播时,我的客户端程序发生异常。

现在,我正在寻找一种更好的方式来寻找客户。我应该使用广播还是多播?我将如何实施?

编辑:使用多个端口不会有问题。但是,我需要能够在单台计算机上运行客户端和服务器。


这是我使用的代码

客户端(控制服务器)

'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



服务器(由客户端控制)

'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

提前致谢!

4

3 回答 3

1

谢谢您的回答。我通过删除手动调用我的客户端的功能来修复它。StartBroadcastUdpThread()

我仍然不明白为什么会发生这种情况。我对客户端和服务器使用完全相同的代码,只是交换了端口。即使StartBroadcastUdpThread()多次调用该方法,TCP 服务器也不会崩溃,客户端会。顺便说一句,无论是先启动客户端还是服务器,都会出现问题。

即使我真的不明白为什么第二次广播会阻止客户端接收广播——它现在已经修复了。谢谢你的帮助!

于 2013-05-21T09:43:47.903 回答
0

最小 UDP 服务器基础:

Imports System.Threading

Shared client As UdpClient
Shared receivePoint As IPEndPoint

client = New UdpClient(2828) 'Port
receivePoint = New IPEndPoint(New IPAddress(0), 0)

Dim readThread As Thread = New Thread(New ThreadStart(AddressOf WaitForPackets))
readThread.Start()

Public Shared Sub WaitForPackets()
    While True
        Dim data As Byte() = client.Receive(receivePoint)
        Console.WriteLine("=" + System.Text.Encoding.ASCII.GetString(data))
    End While
End Sub
于 2015-01-20T13:23:48.923 回答
0

我建议使用 Zeroconf 来查找服务器和客户端,然后使用 TCP 套接字在两者之间进行通信。您可以在此处查看键值对 zeroconf 公告的示例实现:https ://github.com/Eyescale/Lunchbox/blob/master/lunchbox/servus.cpp

于 2013-05-21T08:51:03.720 回答