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

.NET Core与Mono在Linux下UDP广播异常问题求助

问题描述

在Linux环境中观察到异常现象:以下UDP局域网广播代码分别编译为Mono和.NET Core版本,两者看似运行正常,但仅Mono编译版本的UDP数据包可被捕获,.NET Core版本则无法被捕获。

广播器代码实现

public sealed class Broadcaster : IDisposable
{
   readonly IPEndPoint _ipEndPoint;
   readonly object _locker = new object();
   readonly Dictionary<string, UdpClient> _clients = new Dictionary<string, UdpClient>();

   public Broadcaster(ushort broadcastPort)
   {
       _ipEndPoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);
   }

   public void Send(string message)
   {
       var data = Encoding.ASCII.GetBytes(message);
       var host = Dns.GetHostEntry(Dns.GetHostName());
       var addressList = host.AddressList;
       var ip = addressList.Last();
       var ip_ = ip.ToString();
       lock (_locker)
       {
           if (!_clients.ContainsKey(ip_))
               _clients.Add(ip_, new UdpClient(new IPEndPoint(ip, 0)));
       }
       try
       {
           _clients[ip_].SendAsync(data, data.Length, _ipEndPoint);
           Console.WriteLine($"broadcast: {DateTime.UtcNow}");
       }
       catch (Exception ex)
       {
           Console.WriteLine($"unable to use host {ip} while broadcasting: " + ex);
       }
   }

   public void Dispose()
   {
       try
       {
           lock (_locker)
           {
               foreach (var client in _clients)
               {
                   client.Value.Close();
                   client.Value.Dispose();
               }
               _clients.Clear();
           }
       }
       catch (Exception ex)
       {
           Console.WriteLine("Network boadcaster finishing: " + ex);
       }
   }
}  

代码使用示例

static async Task Main(string[] args)
{
    var broadcaster = new Broadcaster(15015);
    while (true)
    {
        broadcaster.Send($"Broadcaster: { DateTime.UtcNow.ToString("HH:mm:ss.fff")}");
        await Task.Delay(1000);
    }
}

已完成的排查操作(Linux无图形化界面,通过bash执行)

  • ufw allow 15005/udp
  • 另一台设备通过Wireshark验证了该现象,且接收应用可正常捕获Mono版本的广播包

疑问

.NET Core版本的广播器存在什么问题?是否需要修改代码或配置Linux权限?Mono与.NET Core的处理差异是什么?


问题分析与解决方案

1. .NET Core版本的核心问题

  • IP地址选择错误:代码通过addressList.Last()选取的IP可能是IPv6地址,Linux下.NET Core的DNS解析默认优先返回IPv6,用IPv6的UdpClient发送IPv4广播(255.255.255.255)会导致跨协议发送失败,无法被捕获。
  • 端口配置不匹配:排查时开放的是15005/udp,但代码中广播端口是15015,防火墙会拦截该端口的数据包。
  • 广播权限未显式启用:.NET Core的UdpClient默认未开启广播权限,而Mono默认开启。
  • 异步操作未等待:原代码中SendAsync未被await,可能导致操作提前终止,数据包未发送完成。

2. 代码修改与配置调整

代码修改

修正IP地址筛选逻辑,显式启用广播权限,并确保异步操作被正确处理:

public void Send(string message)
{
    var data = Encoding.ASCII.GetBytes(message);
    var host = Dns.GetHostEntry(Dns.GetHostName());
    // 筛选出IPv4非回环的局域网地址
    var ip = host.AddressList.FirstOrDefault(a => a.AddressFamily == AddressFamily.InterNetwork && !IPAddress.IsLoopback(a));
    if (ip == null)
    {
        Console.WriteLine("No valid IPv4 network interface found");
        return;
    }
    var ip_ = ip.ToString();
    lock (_locker)
    {
        if (!_clients.ContainsKey(ip_))
        {
            var client = new UdpClient(new IPEndPoint(ip, 0));
            // 显式启用广播权限
            client.EnableBroadcast = true;
            _clients.Add(ip_, client);
        }
    }
    try
    {
        // 使用同步Send确保发送完成,或改为async方法并await SendAsync
        _clients[ip_].Send(data, data.Length, _ipEndPoint);
        Console.WriteLine($"broadcast: {DateTime.UtcNow} from {ip}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"unable to use host {ip} while broadcasting: " + ex);
    }
}

防火墙配置修正

开放代码中实际使用的广播端口:

ufw allow 15015/udp

3. Mono与.NET Core的处理差异

  • DNS解析优先级:Mono在Linux下默认优先返回IPv4地址,.NET Core遵循系统DNS配置,默认优先IPv6。
  • UdpClient默认配置:Mono的UdpClient默认启用广播权限,.NET Core需要显式设置EnableBroadcast = true。
  • 异步操作处理:Mono对未等待的异步操作有更宽松的上下文处理,.NET Core中未等待的异步操作可能被上下文回收,导致操作未完成。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 19:01:52