gpt4 book ai didi

java - 在某些Android设备上严重UDP数据包丢失

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:38:17 31 4
gpt4 key购买 nike

我已经搜索了interwebz,但没有结果。我们面临的问题是某些Android设备会遭受严重的数据包丢失。为了提供一些背景信息,该应用程序连接到特定的Wifi并查找在端口17216上广播的UDP数据包。这些数据包的大小为832字节(不包括包装的 header ),并且以每秒4的常规速率发送。

我们仅在以下两种设备上遇到了问题:低端Turbox Rubik II平板电脑和ASUS Memo Pad HD7。我们测试过的其他设备(手机和平板电脑)均以规定的定期间隔收集数据包。

接收数据包的功能是这样的:

public void run()
{
while (isUDPServerRunning)
{
try
{
socket.receive(packet);

ProcessRawPacketData();

DisplayLoggingInfo();

}
catch (IOException e)
{
Log.e("receive", e.getMessage());
e.printStackTrace();
}
}
}

那是 Runnable的一部分。这样创建了套接字:
byte[] buffer = new byte[1024];

DatagramSocket socket;
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

在我们的 onCreate()扩展的 Service方法中初始化套接字:
socket = new DatagramSocket(SERVERPORT);

Wifi模块正在接收数据包。我们已经确认,通过生根设备之一并安装数据包嗅探器,因此问题一定与代码有关。

在受影响的设备上,数据包会在几秒钟内正确接收,然后完全丢失会持续几秒钟,因此我估计丢失会超过50%。

任何帮助将非常感激。我们正在拔头发。

更新我误认为数据包嗅探器了。似乎数据包嗅探器也在根设备上丢失了几个相关的数据包。但是有时候,仅启动数据包嗅探器即可解决此问题!像下面建议的那样打开/关闭蓝牙似乎没有什么不同。这可能是另一个硬件问题吗?

更新2 这是我在 socket.receive()行之后立即打印的日志的示例。请注意,它如何跳过了半分钟的数据包,然后可以正常工作几秒钟。
05-25 15:44:38.670: D/LOG(4393): Packet Received
05-25 15:44:38.941: D/LOG(4393): Packet Received
05-25 15:45:09.482: D/LOG(4393): Packet Received
05-25 15:45:09.716: D/LOG(4393): Packet Received
05-25 15:45:09.928: D/LOG(4393): Packet Received
05-25 15:45:10.184: D/LOG(4393): Packet Received
05-25 15:45:10.451: D/LOG(4393): Packet Received
05-25 15:45:10.661: D/LOG(4393): Packet Received

最佳答案

数据包丢失(当然,您知道)可能在传输的多个阶段发生:

  • 从服务器发送
  • 通过网络传输
  • 客户端的物理接收和硬件
  • 中的处理
  • 在内核/操作系统中处理/缓冲数据包
  • 在应用程序中处理/缓冲数据包。

  • 您可以让其他设备在连接到同一Wifi路由器时监听同一广播,从而快速检查第1点或第2点是否是问题。听起来您已经这样做了,而且没有问题。 (请注意,如果在服务器上运行,则在WireShark转储中可能不会丢失在步骤2(有时甚至是1)中丢失的数据包。)

    因此,第3点到第5点可能是问题所在,它们可能很难分离。

    以下几件事可能会有所帮助:
  • 就像@Mick所建议的那样,不要只是在收到数据包时打印出来,而是给每个数据包一个递增的ID号,以查明您是否实际上丢失了一个数据包或它只是被延迟了。
  • 将接收数据包的代码移到其自己的线程中(如果尚未移动),并将该线程的set the priority移至MAX_PRIORITY,以最大程度地减少代码阻塞午餐行的机会。鉴于Memo Pad是四核1.2GHz机器,因此甚至没有必要使用MAX_PRIORITY,但是如果您当前尚未在其专用线程中运行接收循环,则可能会遇到问题。如果这可以解决问题,则只需最小的接收循环将数据包粘贴到您自己的缓冲区队列中,并让一个独立的线程对其进行处理。
  • 检查/增加用于通过setReceiveBufferSize(...)(more verbose Java reference here)接收数据包的数据包缓冲区的大小。确保指定的大小可以容纳许多数据包。鉴于运行数据包嗅探器有时似乎可以帮助解决问题,听起来确实有些套接字设置可以改善事情,而嗅探器恰好可以进行设置。
  • 在服务器上,您还可以向数据包添加标签,以告诉所有相关设备如何处理数据包。如果调用setTrafficClass(IPTOS_RELIABILITY),则要求所有相关人员优化其数据包处理,以实现最大的可靠性。并非所有设备都会在意,但可能会有所作为。
  • 您可以尝试使用DatagramChannels代替DatagramSockets,然后使用select()等待下一个数据包的读取。尽管从技术上讲这没有什么区别,但有时使用不同的API调用可以解决问题。
  • 不幸的是,Android是一个非常异构的环境,许多制造商将提供他们自己的内核模块等。这还会在各处引入各种不兼容性或非标准行为。您可能可以为一个或两个问题设备找到一个自定义ROM(Cyanogen等?)。如果安装该设备而不是工厂ROM可以解决问题,那么这是制造商提供的(内核)网络驱动程序中的错误,在这种情况下,您可能会很幸运地找到解决方法,或者可以提交错误报告和它们一起使用,但通常来说,您可能只需要在Play商店中选择不受支持的设备,以免出现不良评论...

  • 最后,这里是一个变通办法,应该可以解决此问题:

    向您的客户端添加一些代码,以检测丢弃的数据包,如果丢弃率太高,则改为打开与服务器的TCP连接,这将保证数据包的传递。鉴于您的数据包很小且不频繁,并且只有少数设备将需要使用此机制,因此我认为这不会给服务器负载造成问题。如果您没有办法更改服务器代码以提供TCP流,则可以编写一个独立的代理服务器来收集UDP数据包并通过TCP使其可用。如果您可以将它与原始服务器在同一台计算机上运行,​​您甚至可以知道它的IP地址(与到达的UDP数据包的源地址相同)。

    关于java - 在某些Android设备上严重UDP数据包丢失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30432974/

    31 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com