为什么Android套接字读取周期性如此缓慢?

时间:2015-06-01 17:25:27

标签: java android sockets inputstream

套接字创建如下:

Socket socket = new Socket();
socket.setReuseAddress(true);
socket.setSoTimeout(iTimeout);
socket.connect(new InetSocketAddress(InetAddress.getByName(uri.getHost()), iPort), 6000);
socket.setReceiveBufferSize(iReceiveBufferSize); //iReceiveBufferSize = 1024*256
final InputStream is = socket.getInputStream();

为了提出这个问题,我们创建并测试了一个调试方法:

public void SocketDebug(InputStream isSocketInput)
{
    try {
        byte[] abBuffer = new byte[1024*256];
        for(int i = 0; i < 1000; i++)
        {
            long lStart = System.currentTimeMillis();
            int iRead = isSocketInput.read(abBuffer, 1024 * 10, 1024 * 128);
            int iElapse = (int)(System.currentTimeMillis() - lStart);
            if(iElapse > 100)
            {
                utility.logd("Debug", "i:" + i + " iElapse:" + iElapse + " iRead:" + iRead);
            }
        }
    }
    catch(Exception ex)
    {

    }
}

以下是logcat记录的内容的一部分:

01-Jun  37:26.8 i:9     iElapse:234 iRead:1448
01-Jun  37:29.5 i:114   iElapse:299 iRead:1448
01-Jun  37:29.8 i:126   iElapse:298 iRead:1448
01-Jun  37:30.1 i:132   iElapse:300 iRead:1448
01-Jun  37:30.4 i:139   iElapse:283 iRead:1448
01-Jun  37:30.7 i:146   iElapse:287 iRead:1448
01-Jun  37:31.0 i:160   iElapse:269 iRead:1448
01-Jun  37:31.3 i:169   iElapse:251 iRead:44888
01-Jun  37:31.5 i:170   iElapse:192 iRead:1448
01-Jun  37:31.7 i:185   iElapse:170 iRead:1448
01-Jun  37:32.0 i:198   iElapse:171 iRead:1448
01-Jun  37:32.2 i:217   iElapse:158 iRead:1448
01-Jun  37:32.5 i:240   iElapse:162 iRead:1448
01-Jun  37:32.7 i:259   iElapse:135 iRead:1448
01-Jun  37:33.0 i:281   iElapse:103 iRead:1448
01-Jun  37:34.2 i:324   iElapse:826 iRead:1448
01-Jun  37:34.4 i:330   iElapse:233 iRead:1448
01-Jun  37:34.7 i:336   iElapse:264 iRead:1448
01-Jun  37:35.0 i:341   iElapse:299 iRead:1448
01-Jun  37:35.3 i:346   iElapse:300 iRead:1448
01-Jun  37:35.6 i:352   iElapse:297 iRead:1448
01-Jun  37:36.0 i:354   iElapse:317 iRead:21720
01-Jun  37:36.3 i:355   iElapse:304 iRead:13032

数据源是视频流服务器。大多数情况下,isSocketInput.read()只需1到3毫秒(上面的日志中没有显示)。但是,周期性地需要100到1000毫秒。查看红色字节数,显然1448是TCP有效负载。所有红色字节的数量都是1448的倍数。人们可能认为服务器发送TCP数据包可能需要很长时间。令人难以理解的是isSocketInput.read()有时会读取如此多的数据包(例如31个数据包= 44888个字节)并且需要很长时间才能返回。当有任何数据时,它是否应该尽快返回?

当运行SocketDebug()时,应用程序的所有其他线程基本上都进入休眠状态(即在包含Thread.sleep()的循环中)。

有人可以提供有关长插座读取时间的可能原因的提示吗?

更新(2015-06-03):

上述测试是使用带有单核CPU(Asus MeMO)的Android平板电脑完成的。当使用具有四核CPU(AGPTek TP714AQ)的低端通用Android平板电脑进行测试时,isSocketInput.read()使用的时间显着改善。在前200次迭代之后,长时间过去的次数减少到零。即使在最初的200次左右的迭代期间,也只有少量的长时间(> 100ms)。

此时此刻,我认为单核CPU设备的长时间过去主要是由于答案中提到的&#34;进程或线程被重新安排&#34; 在单核CPU设备上更频繁地发生这种情况。

1 个答案:

答案 0 :(得分:2)

它无法以比数据到达更快的速度读取,并且不会比发送数据更快地发生。不要责怪接收代码,责怪发件人或网络。

当您获得更多字节数时,可能是在您阻止更长时间之后,并且在您的进程或线程再次重新计划之前到达了更多数据。您无法通过代码控制它。

注意:

  • 您应该在连接之前致电setReceiveBufferSize() ,而不是之后。这样窗口缩放就可以生效了。
  • 如果您没有指定本地端口,则调用setReuseAddress()是没有意义的。