android - 用于通过单跳 Wi-Fi 网络从 Android 设备上传大型二进制文件 (50-200 MB) 的 HTTP 与 Vanilla 套接字

标签 android performance http sockets cherrypy

通过普通套接字(Android 上的 Java)使用 HTTP 将大文件(50-200 MB)[文件在 SD 卡上]从 Android 设备通过 Wi-Fi 发送到 Linux 服务器是否有大量开销?网络。

在我当前的原型(prototype)中,我使用 CherryPy-3.2.0 来实现我的 HTTP 服务器。我作为我的客户端在 Nexus one 上运行 Android 2.3.3。

目前,上传一个 50 MB 的二进制文件大约需要 100 秒**(在较慢的网络 18 Mbps* 上)和约 50 秒(在较快的 54 Mbps* 网络上)。

注意:
*我正在使用 WifiInfo.getLinkSpeed() 测量网络链接速度

** 这是HTTPClient.execute(postRequest)前后的时间差

关于除网络之外的总时间中可能占很大一部分的其他昂贵操作的任何其他想法以及如何减少此时间,我们将不胜感激。

谢谢。

编辑 - Android 上的 HTTP 邮政编码

private void doHttpPost(String fileName) throws Exception{

    HttpParams httpParameters = new BasicHttpParams();

    // Set the timeout in milliseconds until a connection is established.
    int timeoutConnection = 9000000;
    HttpConnectionParams.setConnectionTimeout(httpParameters, timeoutConnection);
    // Set the default socket timeout (SO_TIMEOUT) 
    // in milliseconds which is the timeout for waiting for data.
    int timeoutSocket = 9000000;
    HttpConnectionParams.setSoTimeout(httpParameters, timeoutSocket);

    HttpClient client = new DefaultHttpClient(httpParameters);

    client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.RFC_2109);

    HttpPost postRequest = new HttpPost();
    postRequest.setURI(new URI("http://192.168.1.107:9999/upload/"));

    MultipartEntity multiPartEntity = new MultipartEntity();
    multiPartEntity.addPart("myFile", new FileBody(new File(fileName)));
    postRequest.setEntity(multiPartEntity);

    long before = TrafficStats.getTotalTxBytes();
    long start = System.currentTimeMillis();
    HttpResponse response = client.execute(postRequest);
    long end = System.currentTimeMillis(); 
    long after = TrafficStats.getTotalTxBytes();

    Log.d(LOG_TAG, "HTTP Post Execution took " + (end - start) + " ms.");


    if( before != TrafficStats.UNSUPPORTED && after != TrafficStats.UNSUPPORTED)
        Log.d(LOG_TAG, (after-before) + " bytes transmitted to the server");
    else
        Log.d(LOG_TAG, "This device doesnot support Network Traffic Stats");

    HttpEntity responseEntity = response.getEntity();


    if (responseEntity != null) {
        responseEntity.consumeContent();
        Log.d(LOG_TAG, "HTTP Post Response " + response.getEntity().getContent().toString() );
    }

    client.getConnectionManager().shutdown(); 

}

编辑 2:根据此工具报告的结果,SD 卡读取速度似乎不是问题。所以它可能是 HttpClient 库或其他东西。 enter image description here enter image description here

最佳答案

HTTP 连接的开销来自它与您的数据一起发送的 header (这基本上是一个常量)。所以你发送的数据越多,标题“伤害你”的就越少。但是,要考虑的更重要的方面是编码

例如,如果您要发送非 ASCII 数据,并与 application/x-www-form-urlencoded 的 mime 类型配对,您将面临输入大小爆炸的风险,因为非 ASCII字符必须转义。

来自spec :

The content type "application/x-www-form-urlencoded" is inefficient for sending large quantities of binary data or text containing non-ASCII characters. The content type "multipart/form-data" should be used for submitting forms that contain files, non-ASCII data, and binary data.

替代方法是 multipart/form-data,它对二进制数据很有效。因此,请确保您的应用程序使用的是这种 MIME 类型(您甚至可以在服务器日志中检查这一点)。

另一种可以大大减少上传时间的方法是压缩。如果您正在上传尚未压缩的数据(大多数图像和视频格式已经压缩),请尝试为您的上传添加 gzip 压缩。 Another post显示了在 android 中设置它的详细信息。

如果您的数据是特定格式(比如图像),您可以研究适合您的数据类型的无损压缩算法(图像为 png,音频为 FLAC,等等)。压缩总是以 CPU(电池)为代价,所以请记住这一点。

记住:

在您知道它的瓶颈之前不要优化它。也许你的服务器连接速度很慢,也许你无法以足够快的速度从 android 文件系统中读取数据以将数据推送到网络。运行一些测试,看看有什么效果。

如果是我,我不会实现直接的 tcp 方法。只需我的 2 美分,祝你好运!

关于android - 用于通过单跳 Wi-Fi 网络从 Android 设备上传大型二进制文件 (50-200 MB) 的 HTTP 与 Vanilla 套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5547040/

相关文章:

java - Android 反序列化 Arraylist 的速度问题

javascript - 解决矛盾的 Cache-Control header

Android - 获取可见矩形的百分比

android - 如何将 TensorFlow JSON 图形模型转换为 .tflite?

java - 任务 ':app:mergeExtDexDebug' 执行失败

android - 如何在对话框 ListView 中设置 onItemClickListener()?

c++ - 为什么我的程序在大输入时失败?超过 10^5

c++ - 我可以在类源文件的单独源文件中定义成员函数吗?

http - Firefox 在加载一个网站时总是显示旋转轮,没有内容出现

c# - 是否有 C# 或 .NET 类来处理 HTTP 内容协商?