无法在 Xamarin.Forms 应用程序中接收 UDP 广播
unable to receive UDP broadcast in Xamarin.Forms app
我创建了一个测试 Xamarin.Forms 项目,选项卡式应用程序,支持 iOS、Android 和 UWP。具有样板起始代码的应用程序在所有 3 个平台上都能正确构建和 运行s。
我正在尝试在应用程序中测试接收 UDP 广播。 UDP 广播是从同一子网上的另一台机器发送的(已经测试了来自另一台机器和同一台机器的广播,结果相同)。如果我在这台机器上 运行 一个独立的、非托管的 UDP 侦听器测试工具(我们内部编写的一个),我可以看到来自另一台机器的所有消息。
我将代码(如下所示)添加到 Xamarin.Forms 项目和 运行 本机上的 UWP 构建。 我看到的是,在调试输出中我收到了 "started receiving" 消息,然后没有其他消息。 我实际上没有收到消息(或者至少,回调未被调用)。我检查了 netstat,可以看到当我的 Xamarin.Forms 应用程序处于 运行ning 时,它绑定到指定的 UDP 端口。但是我的 OnUdpDataReceived 从未被调用过。
编辑: 我在解决方案资源管理器中双击 UWP 项目的 Package.appxmanifest 文件,它显示了一个 UI 并且我检查了 "Capabilities >> Internet (Client & Server)" 认为这是一个权限问题,但这没有帮助。
编辑: 我通过创建两个控制台项目(一个发送方和一个接收方)验证了连通性。发件人只是永远循环,每秒发送一个测试 UDP 广播。接收器使用此处显示的相同代码。这些项目按预期工作。因此,相同的接收器代码在控制台项目中有效,但在 Xamarin.Forms 项目中无效。
首先是一个简单的UDP接收器class.
public class BaseUdpReceiver
{
private UdpClient _udpClient;
public BaseUdpReceiver()
{
}
public void Start()
{
_udpClient = new UdpClient()
{
ExclusiveAddressUse = false,
EnableBroadcast = true
};
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, Constants.Network.SOME_CONSTANT_PORT_INTEGER));
_udpClient.BeginReceive(OnUdpDataReceived, _udpClient);
Debug.WriteLine($">>> started receiving");
}
private static void OnUdpDataReceived(IAsyncResult result)
{
Debug.WriteLine($">>> in receive");
var udpClient = result.AsyncState as UdpClient;
if (udpClient == null)
return;
IPEndPoint remoteAddr = null;
var recvBuffer = udpClient.EndReceive(result, ref remoteAddr);
Debug.WriteLine($"MESSAGE FROM: {remoteAddr.Address}:{remoteAddr.Port}, MESSAGE SIZE: {recvBuffer?.Length ?? 0}");
udpClient.BeginReceive(OnUdpDataReceived, udpClient);
}
}
然后,App.xaml.cs中的代码使用了这个class。
public partial class App : Application
{
private BaseUdpReceiver _udpReceiver;
public App()
{
InitializeComponent();
DependencyService.Register<MockDataStore>();
MainPage = new MainPage();
_udpReceiver = new BaseUdpReceiver();
_udpReceiver.Start();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
版本信息
Visual Studio 2019 Enterprise v16.4.5
Xamarin 16.4.000.322 (d16-4@ddfd842)
Windows 10 64-bit v1909 (OS Build 18363.657)
Microsoft.NETCore.UniversalWindowsPlatform, v6.2.9
NETStandard.Library, v2.0.3
Xamarin.Essentials, v1.5.0
Xamarin.Forms, v4.5.0.356
在 MS 支持的帮助下,它适用于 UWP 和 Android。
请注意,考虑到以下因素,原始 post 中提供的代码是正确且有效的。
- UWP
- 由于 UWP 的网络隔离,你不能在同一台机器上广播和接收,虽然这在控制台应用程序中工作正常,但它不适用于 Xamarin.Forms UWP,所以技巧是你只需要从不同的机器广播
- 需要调整Package.appxmanifest>>能力设置
- 在 2 台机器上(wifi 笔记本电脑和有线台式机),我发现检查 "Internet (Client)" 和 "Internet (Client & Server)" 就足够了
- 在具有 2 个网卡的第 3 台台式机上,一个插入一个拔出,它仍然无法使用上述选项,还需要检查 "Private Networks (Client & Server)"
- Android
- 模拟器似乎创建了自己的子网,您可以通过检查模拟器的网络设置看到这一点,它显然与 运行[=34= 所在的桌面计算机不在同一个子网中]
- 因此,您无法在 Android 模拟器中以简单的方式获得 UDP 广播(除了我没有试验过的某种转发方案)
- 已验证使用物理 Android 平板电脑(使用 Samsung Galaxy Tab A 8" 测试),它可以工作并且我能够接收 UDP 广播
- 请注意,在 Android 上,我不必像使用 UWP 那样更改默认设置的任何权限,它可以正常工作
- iOS
- 到目前为止,还没有在物理 iOS 设备上测试过,我有一个 iPhone,但我使用的是云 Mac 构建服务器,所以无法测试在我的设备上
- 到了处理 iOS 的时候,看来我可能需要找一个本地 Mac
我创建了一个测试 Xamarin.Forms 项目,选项卡式应用程序,支持 iOS、Android 和 UWP。具有样板起始代码的应用程序在所有 3 个平台上都能正确构建和 运行s。
我正在尝试在应用程序中测试接收 UDP 广播。 UDP 广播是从同一子网上的另一台机器发送的(已经测试了来自另一台机器和同一台机器的广播,结果相同)。如果我在这台机器上 运行 一个独立的、非托管的 UDP 侦听器测试工具(我们内部编写的一个),我可以看到来自另一台机器的所有消息。
我将代码(如下所示)添加到 Xamarin.Forms 项目和 运行 本机上的 UWP 构建。 我看到的是,在调试输出中我收到了 "started receiving" 消息,然后没有其他消息。 我实际上没有收到消息(或者至少,回调未被调用)。我检查了 netstat,可以看到当我的 Xamarin.Forms 应用程序处于 运行ning 时,它绑定到指定的 UDP 端口。但是我的 OnUdpDataReceived 从未被调用过。
编辑: 我在解决方案资源管理器中双击 UWP 项目的 Package.appxmanifest 文件,它显示了一个 UI 并且我检查了 "Capabilities >> Internet (Client & Server)" 认为这是一个权限问题,但这没有帮助。
编辑: 我通过创建两个控制台项目(一个发送方和一个接收方)验证了连通性。发件人只是永远循环,每秒发送一个测试 UDP 广播。接收器使用此处显示的相同代码。这些项目按预期工作。因此,相同的接收器代码在控制台项目中有效,但在 Xamarin.Forms 项目中无效。
首先是一个简单的UDP接收器class.
public class BaseUdpReceiver
{
private UdpClient _udpClient;
public BaseUdpReceiver()
{
}
public void Start()
{
_udpClient = new UdpClient()
{
ExclusiveAddressUse = false,
EnableBroadcast = true
};
_udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
_udpClient.Client.Bind(new IPEndPoint(IPAddress.Any, Constants.Network.SOME_CONSTANT_PORT_INTEGER));
_udpClient.BeginReceive(OnUdpDataReceived, _udpClient);
Debug.WriteLine($">>> started receiving");
}
private static void OnUdpDataReceived(IAsyncResult result)
{
Debug.WriteLine($">>> in receive");
var udpClient = result.AsyncState as UdpClient;
if (udpClient == null)
return;
IPEndPoint remoteAddr = null;
var recvBuffer = udpClient.EndReceive(result, ref remoteAddr);
Debug.WriteLine($"MESSAGE FROM: {remoteAddr.Address}:{remoteAddr.Port}, MESSAGE SIZE: {recvBuffer?.Length ?? 0}");
udpClient.BeginReceive(OnUdpDataReceived, udpClient);
}
}
然后,App.xaml.cs中的代码使用了这个class。
public partial class App : Application
{
private BaseUdpReceiver _udpReceiver;
public App()
{
InitializeComponent();
DependencyService.Register<MockDataStore>();
MainPage = new MainPage();
_udpReceiver = new BaseUdpReceiver();
_udpReceiver.Start();
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}
版本信息
Visual Studio 2019 Enterprise v16.4.5
Xamarin 16.4.000.322 (d16-4@ddfd842)
Windows 10 64-bit v1909 (OS Build 18363.657)
Microsoft.NETCore.UniversalWindowsPlatform, v6.2.9
NETStandard.Library, v2.0.3
Xamarin.Essentials, v1.5.0
Xamarin.Forms, v4.5.0.356
在 MS 支持的帮助下,它适用于 UWP 和 Android。
请注意,考虑到以下因素,原始 post 中提供的代码是正确且有效的。
- UWP
- 由于 UWP 的网络隔离,你不能在同一台机器上广播和接收,虽然这在控制台应用程序中工作正常,但它不适用于 Xamarin.Forms UWP,所以技巧是你只需要从不同的机器广播
- 需要调整Package.appxmanifest>>能力设置
- 在 2 台机器上(wifi 笔记本电脑和有线台式机),我发现检查 "Internet (Client)" 和 "Internet (Client & Server)" 就足够了
- 在具有 2 个网卡的第 3 台台式机上,一个插入一个拔出,它仍然无法使用上述选项,还需要检查 "Private Networks (Client & Server)"
- Android
- 模拟器似乎创建了自己的子网,您可以通过检查模拟器的网络设置看到这一点,它显然与 运行[=34= 所在的桌面计算机不在同一个子网中]
- 因此,您无法在 Android 模拟器中以简单的方式获得 UDP 广播(除了我没有试验过的某种转发方案)
- 已验证使用物理 Android 平板电脑(使用 Samsung Galaxy Tab A 8" 测试),它可以工作并且我能够接收 UDP 广播
- 请注意,在 Android 上,我不必像使用 UWP 那样更改默认设置的任何权限,它可以正常工作
- iOS
- 到目前为止,还没有在物理 iOS 设备上测试过,我有一个 iPhone,但我使用的是云 Mac 构建服务器,所以无法测试在我的设备上
- 到了处理 iOS 的时候,看来我可能需要找一个本地 Mac