You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过广播快速发现树莓派上指定端口的Web服务器?

用UDP广播快速发现树莓派上的.NET Web服务

一、先搞定树莓派端的广播发送(Docker里的.NET服务)

你的Web服务跑在Docker容器里,首先得处理网络问题——要么让容器共享主机网络,要么把UDP广播端口映射出来,不然局域网里的MAUI设备收不到广播信号。

1. Docker端口/网络配置

  • 图省事的话,直接让容器复用主机网络,运行容器时加--network host参数,这样容器里的端口和主机端口完全一致,不用单独映射:
    docker run -d --network host --name your-web-service your-image
    
  • 要是不想用主机网络,就同时映射Web服务端口(7299)和UDP广播端口(比如设为7300):
    docker run -d -p 7299:7299 -p 7300:7300/udp --name your-web-service your-image
    

2. 在.NET Web服务里加广播逻辑

写个后台定时发送广播的服务,主动告诉局域网里的设备“我在这,我的地址是XX”:

using System.Net;
using System.Net.Sockets;
using System.Text;

public class UdpBroadcaster : BackgroundService
{
    private readonly ILogger<UdpBroadcaster> _logger;
    // 广播专用端口,要和MAUI客户端保持一致
    private const int BroadcastPort = 7300;
    // 自定义服务标识,避免和其他设备的广播消息混淆
    private const string ServiceTag = "RPI_DOTNET_WEB";
    // 你的Web服务端口
    private readonly string _webPort = "7299";

    public UdpBroadcaster(ILogger<UdpBroadcaster> logger)
    {
        _logger = logger;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        using var udpClient = new UdpClient { EnableBroadcast = true };
        var broadcastPoint = new IPEndPoint(IPAddress.Broadcast, BroadcastPort);

        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
                // 获取设备的局域网IP(用host网络的话就是树莓派本身的IP)
                var localIp = GetLanIp();
                // 拼接消息:服务标识;IP地址;Web端口
                var broadcastMsg = $"{ServiceTag};{localIp};{_webPort}";
                var msgBytes = Encoding.UTF8.GetBytes(broadcastMsg);
                
                await udpClient.SendAsync(msgBytes, msgBytes.Length, broadcastPoint);
                _logger.LogInformation("发送广播:{Msg}", broadcastMsg);
                // 每5秒发一次,可根据需求调整频率
                await Task.Delay(5000, stoppingToken);
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "广播发送失败");
                await Task.Delay(1000, stoppingToken);
            }
        }
    }

    private IPAddress GetLanIp()
    {
        var hostEntry = Dns.GetHostEntry(Dns.GetHostName());
        foreach (var ip in hostEntry.AddressList)
        {
            // 筛选非回环的IPv4地址
            if (ip.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
            {
                return ip;
            }
        }
        throw new InvalidOperationException("没找到有效的局域网IP");
    }
}

然后在Program.cs里注册这个后台服务:

builder.Services.AddHostedService<UdpBroadcaster>();

二、.NET MAUI端的监听逻辑

MAUI这边要监听指定端口的UDP广播,收到消息后解析出服务器的地址和端口。

1. 写监听代码

可以把逻辑放在ViewModel里,方便和页面绑定:

using System.Net;
using System.Net.Sockets;
using System.Text;
using CommunityToolkit.Mvvm.ComponentModel;

public partial class ServiceDiscoveryVm : ObservableObject
{
    private const int BroadcastPort = 7300;
    private const string ServiceTag = "RPI_DOTNET_WEB";
    private UdpClient _udpListener;
    private CancellationTokenSource _cancelTokenSource;

    [ObservableProperty]
    private string _serverUrl;

    public async Task StartSearching()
    {
        _cancelTokenSource = new CancellationTokenSource();
        _udpListener = new UdpClient(BroadcastPort);
        // 允许重复绑定端口,避免多个应用监听时冲突
        _udpListener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

        try
        {
            while (!_cancelTokenSource.Token.IsCancellationRequested)
            {
                var receiveResult = await _udpListener.ReceiveAsync(_cancelTokenSource.Token);
                var receivedMsg = Encoding.UTF8.GetString(receiveResult.Buffer);
                var parts = receivedMsg.Split(';');

                // 验证消息是我们的树莓派服务发的
                if (parts.Length == 3 && parts[0] == ServiceTag)
                {
                    var serverIp = parts[1];
                    var serverPort = parts[2];
                    ServerUrl = $"http://{serverIp}:{serverPort}";
                    // 找到服务后可以停止监听,也可以继续监听应对IP变化
                    // _cancelTokenSource.Cancel();
                }
            }
        }
        catch (OperationCanceledException)
        {
            // 监听被取消,正常结束
        }
        catch (Exception ex)
        {
            // 这里可以加异常提示,比如弹窗告诉用户搜索失败
        }
        finally
        {
            _udpListener?.Close();
            _udpListener?.Dispose();
        }
    }

    public void StopSearching()
    {
        _cancelTokenSource?.Cancel();
    }
}

2. 在页面里调用监听

在页面的生命周期事件里启动和停止监听:

protected override async void OnAppearing()
{
    base.OnAppearing();
    await ViewModel.StartSearching();
}

protected override void OnDisappearing()
{
    base.OnDisappearing();
    ViewModel.StopSearching();
}

三、要注意的细节

  • 权限配置:MAUI应用需要网络权限,Android要在AndroidManifest.xml中添加:
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
    iOS要在Info.plist中添加:
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    
  • Docker网络坑:如果不用--network host,容器内部的IP可能不是树莓派的局域网IP,这时候可以把树莓派的IP作为环境变量传给容器,广播时直接用这个IP。比如启动容器时加-e HOST_IP=192.168.xxx.xxx,然后在广播服务里读取这个环境变量。
  • 广播频率:不要太频繁发广播,5秒一次足够,太密会占用局域网带宽;也不要太疏,不然MAUI启动后要等很久才能发现服务。

内容的提问来源于stack exchange,提问作者Hickori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 00:11:10