某些Android设备上的严重UDP数据包丢失

我已经搜遍了互联网,没有结果。 我们正面临一些Android设备遭遇严重丢包的问题。 为了提供一些背景知识,应用程序连接到特定的Wifi并查找在端口17216上广播的UDP数据包。这些数据包的大小为832字节,不包括封装的标题,并且以每秒四次的正常速率发送。

我们只在两台设备上遇到了问题,一台是低端Turbox Rubik II平板电脑和一台华硕备忘录HD 7.我们testing过的其他设备(手机和平板电脑)都按照规定的时间间隔收集数据包。

接收数据包的函数是这样的:

public void run() { while (isUDPServerRunning) { try { socket.receive(packet); ProcessRawPacketData(); DisplayLoggingInfo(); } catch (IOException e) { Log.e("receive", e.getMessage()); e.printStackTrace(); } } } 

这是一个Runnable一部分。 套接字是这样创build的:

 byte[] buffer = new byte[1024]; DatagramSocket socket; DatagramPacket packet = new DatagramPacket(buffer, buffer.length); 

套接字在Service扩展的onCreate()方法中被初始化:

 socket = new DatagramSocket(SERVERPORT); 

数据包正在被Wifi模块接收。 我们已经证实,通过扎根其中一个设备并安装一个数据包嗅探器,所以这个问题必须是代码相关的。

在受影响的设备上,包被正确接收几秒钟,然后有完整的丢包持续几秒钟,所以我估计损失超过50%。

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

更新我误解了数据包嗅探器。 看起来,数据包嗅探器在根设备上也丢失了几个相关的数据包。 有时候 ,简单地启动数据包嗅探器可以解决问题! 打开/closures蓝牙,如下所示,似乎没有什么区别。 这可能是另一个硬件问题吗?

更新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 

Solutions Collecting From Web of "某些Android设备上的严重UDP数据包丢失"

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

  1. 从服务器发送
  2. 通过networking传输
  3. 客户端的实际接收和硬件处理
  4. 处理/缓冲内核/ OS中的数据包
  5. 处理/缓冲您的应用程序中的数据包。

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

第3点到第5点因此可能是问题,他们可能有点难以分离出来。

以下是一些可能有所帮助的事情:

  • 就像@Mick所build议的那样,不要只是收到数据包打印出来,而是要给每个数据包增加一个ID号码,以确定是否真的丢失了一个数据包,还是只是延迟了数据包。
  • 将您的数据包接收代码移动到它自己的线程中(如果还没有的话), 并将该线程的优先级设置为MAX_PRIORITY,以最大限度地减less代码阻塞午餐线的机会。 鉴于备忘垫是一个四核1.2GHz的机器,MAX_PRIORITY甚至不是必需的,但是如果您目前没有在自己的专用线程中运行接收环路,那么无论如何您都可能会看到小心。 如果这样做可以解决问题,只需要一个最小的接收循环将数据包粘贴到您自己的缓冲队列中,并由一个独立的线程来处理它们。
  • 通过setReceiveBufferSize(…)检查/增加接收数据包的数据包缓冲区的大小( 这里有更详细的Java引用 )。 确保你指定了一个可以容纳很多数据包的大小。 鉴于运行包嗅探器有时似乎有助于事情,听起来好像可能有一些套接字设置,可以改善嗅探器正好设置的东西。
  • 在服务器上,您还可以在数据包中添加一个标签,告诉所有相关设备如何处理数据包。 如果您调用setTrafficClass(IPTOS_RELIABILITY) ,则要求所有参与者优化其数据包处理以获得最大的可靠性。 并不是所有的设备都会照顾,但它可能会有所作为。
  • 您可以尝试使用DatagramChannel而不是DatagramSockets,然后使用select()等待下一个数据包的读取。 虽然这在技术上不应该有所作为,有时使用不同的API调用可以提供解决问题的方法。
  • 不幸的是,Android是一个非常异类的环境,很多制造商都会提供自己的内核模块等。这也引发了各种不兼容或者不规范的行为。 你可以find一个或两个你的问题设备自定义ROM(氰基等?)。 如果安装而不是工厂ROM修复你的问题,那么这是在制造商提供的(内核)networking驱动程序的错误,在这种情况下,你可能很幸运find解决办法,或者你可以提交一个错误报告与他们,但一般来说,你可能只需要select这些设备不支持在Play商店,以避免不好的评论…

最后,这是一个解决问题的方法:

将一些代码添加到客户端,以检测丢弃的数据包,如果丢失率过高,则会打开与服务器的TCP连接,从而保证数据包的传输。 鉴于你的数据包很小,很less,只有less数设备需要使用这种机制,我不认为这应该会导致您的服务器负载的问题。 如果您没有办法更改服务器代码以提供TCPstream,则可以编写一个独立的代理服务器来收集UDP数据包,并通过TCP使其可用。 如果您可以在与原始服务器相同的机器上运行它,您甚至可以知道它所在的IP地址(与到达的UDP数据包的源地址相同)。

只是一个疯狂的猜测,但你的包计算多长时间? 是否有可能为套接字分配的缓冲区填满并开始丢弃包?

我知道,对于大约4 KB / s的传输速率来说这听起来不太可能…但是如果您的计算时间超过250毫秒,则迟早会发生。 这也可以解释为什么有些设备像魅力一样工作,而其他设备则不行。

你有没有试图删除计算,只是打印“包收到”消息进行debugging?

有趣的是,遇到UDP数据包丢失的设备都碰巧有Mediatek SoC。 你的其他testing设备是否有这个相同的芯片组?

这可能是这些SoC的Wi-Fi驱动程序的一个缺陷。 因为它只是用UDP来显示的,并不总是100%,所以到现在为止可能都没有人注意到。

这听起来非常类似蓝牙干扰症状,可以在Android(和iOS – 实际上任何与WiFi和蓝牙一起)设备上看到。

2.4Ghz的WiFi和蓝牙共享相同的带宽,可以互相干扰 – 在某些设备上这是vey发音,也许是由于内部布局。

也有可能你可以在一些设备上看到它,而不是其他的,因为它们支持的WiFi版本 – 基于5GHz的较新的wifi不会以同样的方式干扰蓝牙,但是一些老的或更基本的Android设备可能不支持这个。

您可以通过在testing时closures设备上的蓝牙(如果您的应用程序可以在没有蓝牙的情况下运行)来轻松testing这是否是原因。