在空闲端口上发送/接收UDP

本文关键字:接收 UDP | 更新日期: 2023-09-27 18:17:40

在一个项目中,有一个设备监听特定的UDP端口并响应发送方端口。

对于发送方和接收方,我希望系统选择一个空闲端口,因此我有以下代码:

[请原谅大量的代码,但这是显示行为发生的最小示例]

发送代码:

public class UdpSender
{
    public int Port = 0; // some initially random port
    public UdpClient UdpServer { get; set; }
    public UdpSender()
    {
        UdpServer = CreateUdpClient();
        // save the portnumber chosen by system to reuse it
        Port = ((IPEndPoint)(UdpServer.Client.LocalEndPoint)).Port;
    }
    private UdpClient CreateUdpClient()
    {
        if (UdpServer != null)
        {
            UdpServer.Close();
        }
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Port);
        var udpServer = new UdpClient();
        udpServer.ExclusiveAddressUse = false;
        udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.Client.Bind(localEndPoint);
        return udpServer;
    }
    public void Send(byte[] arr)
    {
        UdpServer = CreateUdpClient();
        int remotePortNumber = 6565;
        var remoteEndPoint = new IPEndPoint(IPAddress.Broadcast, remotePortNumber);
        try
        {
            UdpServer.Send(arr, arr.Length, remoteEndPoint);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        UdpServer.Close();
    }
}
接收代码:

public class UDPListener
{
    private static int portNumber;
    private UdpClient udpClient = null;
    public List<DeviceData> DeviceList = new List<DeviceData>();
    public UDPListener(int port)
    {
        portNumber = port;
        IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, portNumber);
        udpClient = new UdpClient();
        udpClient.ExclusiveAddressUse = false;
        udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpClient.Client.Bind(localEndPoint);
        udpClient.Client.ReceiveBufferSize = 1 << 23;
    }
    public void StartListening()
    {
        this.udpClient.BeginReceive(Receive, new object());
    }
    private void Receive(IAsyncResult ar)
    {
        IPEndPoint ip = new IPEndPoint(IPAddress.Any, portNumber);
        byte[] bytes = udpClient.EndReceive(ar, ref ip);
        string message = Encoding.ASCII.GetString(bytes);
        DeviceList.Add(new DeviceData(message));
        StartListening();
    }
}

合并:

public class DeviceFinder
{
    public IEnumerable<DeviceData> Find()
    {
        var sender = new UdpSender();
        int port = sender.Port;
        var listener = new UDPListener(port);
        listener.StartListening();
        sender.Send(new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
        System.Threading.Thread.Sleep(5000); // wait some time for answers
        return listener.DeviceList;
    }
}

使用这种方法永远不会调用Receive方法。但是在Wireshark中,我可以看到来自设备的答案。

这种方法有什么问题?

在使用这种方法之前,我已经使用了一个固定端口,并且还添加了对CreateUdpClient的调用。似乎与此有关,但我不明白。之前,我刚刚创建了一个UdpClient与固定端口内的接收/发送方法。

前面的版本可以在这个问题中看到。这是完美的。但是我担心如果固定端口已经在使用中,它不起作用,因此采用这种新方法。

在空闲端口上发送/接收UDP

只需指定零作为您自己的端口号。当您绑定或发送时,系统将分配一个。源端口号将伴随数据报到对等端,对等端应该对其进行回复。