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

Flutter中RawDatagramSocket.listen无法接收UDP包问题排查

UDP监听异常:Flutter客户端无法接收UDP包但PowerShell可正常接收

背景

我希望两个Flutter客户端通过dart:io的RawDatagramSocket实现UDP Socket数据互传,双方已知彼此的监听IP地址和端口。

当前问题

向同一局域网内的Flutter客户端发送UDP包时,socket.listen()方法无法接收数据包;但无论是从PowerShell窗口还是Flutter客户端向PowerShell UDP监听器发送数据包,都能被正常接收并读取。

Flutter客户端代码

以下客户端监听1338端口,发送数据包后listen无输出,说明未接收成功:

class ChatCubit extends Cubit<ChatState> {
  ChatCubit() : super(ChatLoading());

  String addressValue = '目标机器IP';

  late RawDatagramSocket udpSocket;

  Future main() async {
    udpSocket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 1338);
    udpSocket.broadcastEnabled = true;

    print('############# 监听消息中 #############');

    udpSocket.listen((event) {
      print("recv e: $event");
      if (event == RawSocketEvent.read) {
        print(utf8.decode(udpSocket.receive()!.data));
      }
    }, onError: (error) {
      print("error: $error");
    }, onDone: () {
      print("done!");
    }, cancelOnError: true);

    print('${udpSocket.address.address}:${udpSocket.port}');
  }

  void sendMessage(String basicMessage) async {
    print('############# 发送消息中 #############');

    udpSocket.send(const Utf8Codec().encode(basicMessage), InternetAddress(addressValue), 1337);
  }
}

PowerShell发送端脚本

使用该脚本向Flutter客户端发送UDP包,客户端无接收响应:

function Send-UdpDatagram
{
      Param ([string] $EndPoint, 
      [int] $Port, 
      [string] $Message)

      $IP = [System.Net.Dns]::GetHostAddresses($EndPoint) 
      $Address = [System.Net.IPAddress]::Parse($IP) 
      $EndPoints = New-Object System.Net.IPEndPoint($Address, $Port) 
      $Socket = New-Object System.Net.Sockets.UDPClient 
      $EncodedText = [Text.Encoding]::ASCII.GetBytes($Message) 
      $SendMessage = $Socket.Send($EncodedText, $EncodedText.Length, $EndPoints) 
      $Socket.Close() 
} 

执行命令:Send-UdpDatagram -EndPoint "目标机器IP" -Port 1338 -Message "test.mymetric:0|c"

PowerShell接收端脚本

该脚本监听1338端口,无论是Flutter客户端(监听1337、发送到1338)还是PowerShell发送端发送的数据包,都能成功接收:

param( $address="Any", $port=1338)


try{
    $endpoint = new-object System.Net.IPEndPoint( [IPAddress]::$address, $port )
    $udpclient = new-object System.Net.Sockets.UdpClient $port
}
catch{
    throw $_
    exit -1
}

Write-Host "按ESC停止UDP服务器 ..." -fore yellow
Write-Host ""
while( $true )
{
    if( $host.ui.RawUi.KeyAvailable )
    {
        $key = $host.ui.RawUI.ReadKey( "NoEcho,IncludeKeyUp,IncludeKeyDown" )
        if( $key.VirtualKeyCode -eq 27 )
        {    break    }
    }

    if( $udpclient.Available )
    {
        $content = $udpclient.Receive( [ref]$endpoint )
        Write-Host "$($endpoint.Address.IPAddressToString):$($endpoint.Port) $([Text.Encoding]::ASCII.GetString($content))"
    }
}

$udpclient.Close( )

核心疑问

为何Flutter客户端或PowerShell向PowerShell监听器发送数据正常,但向Flutter客户端发送UDP包时,其监听却无法接收?


问题排查与解决方案

1. 防火墙拦截

这是最常见的原因:PowerShell作为系统自带程序,默认已被防火墙允许接收UDP数据包;而Flutter应用(尤其是桌面或移动应用)可能未被添加到防火墙的允许列表中,导致入站UDP流量被拦截。

解决方法:

  • 打开系统防火墙设置,添加Flutter应用的入站规则,允许UDP端口1338的流量通过。
  • 临时关闭防火墙测试,确认是否是防火墙导致的问题。

2. 网络权限缺失

如果是移动平台(Android/iOS)的Flutter应用,需要配置相应的网络权限才能接收UDP数据包:

  • Android:在AndroidManifest.xml中添加<uses-permission android:name="android.permission.INTERNET"/>
  • iOS:确保Info.plist中配置了允许网络访问的权限(UDP不受ATS限制,但需应用具备基础网络权限)

3. 事件处理逻辑遗漏

RawDatagramSocket的listen回调会触发多种事件类型,除了RawSocketEvent.read,还可能有RawSocketEvent.closed、RawSocketEvent.write等。可以先打印所有事件类型,确认是否有数据包到达的相关事件:

udpSocket.listen((event) {
  print("触发事件: $event"); // 打印所有事件,确认是否有read事件
  if (event == RawSocketEvent.read) {
    var datagram = udpSocket.receive();
    if (datagram != null) {
      print("接收数据: ${utf8.decode(datagram.data)}");
    }
  }
});

另外,注意udpSocket.receive()会移除队列中的数据包,如果有多个read事件,确保每次都正确处理。

4. 编码不匹配(导致解码失败而非接收失败)

PowerShell发送端使用ASCII编码,而Flutter用utf8.decode解码。虽然这不会导致接收不到数据包,但可能会出现解码乱码,让你误以为没接收成功。可以统一编码:

  • Flutter端改用ascii.decode(datagram.data)
  • 或PowerShell端改用UTF8编码:$EncodedText = [Text.Encoding]::UTF8.GetBytes($Message)

5. 绑定地址问题

虽然代码中用了InternetAddress.anyIPv4(即0.0.0.0,监听所有网卡),但某些系统环境下可能存在多个网卡,导致数据包未到达Flutter绑定的网卡。可以尝试绑定到具体的局域网IP而非anyIPv4:

udpSocket = await RawDatagramSocket.bind(InternetAddress("你的局域网IP"), 1338);

内容的提问来源于stack exchange,提问作者Angelo-Br

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 03:10:25