HTTP Vs sockets Vanilla para cargar archivos binarios grandes (50-200 MB) desde un dispositivo Android a través de una red Wi-Fi de un solo salto
¿Hay una sobrecarga sustancial de usar HTTP sobre sockets normales (Java en Android) para enviar un archivo grande (50-200 MB) desde un dispositivo Android a un servidor Linux a través de una red Wi-Fi.
En mi prototipo actual estoy usando CherryPy-3.2.0 para implementar mi servidor HTTP. Estoy ejecutando Android 2.3.3 en un Nexus uno como mi cliente.
- Proteger un socket en VpnService
- Android - Socket del servidor
- Mensajes de error NetlinkListener y NetlinkEvent
- Java socket IOException - permiso denegado
- El arranque del emulador atascó la estructura x86 en AOSP 4.3 con el emulador: Error al conectar con el zócalo '127.0.0.1:1970'
Actualmente se tarda unos ~ 100 segundos ** (en la red más lenta 18 Mbps *) y ~ 50 segundos (en una más rápida de 54 Mbps *) de red Wi-Fi para cargar un archivo binario de 50 MB.
NOTA:
* Estoy usando WifiInfo.getLinkSpeed()
para medir la velocidad del enlace de red
** Esta es la diferencia de tiempo antes y después del HTTPClient.execute(postRequest)
Cualquier otra idea con respecto a otras operaciones caras que pueden tener una parte sustancial en el tiempo total aparte de la red y cómo reducir este tiempo sería apreciada.
Gracias.
EDITAR – Código postal HTTP en Android
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(); }
EDIT 2: Basado en los resultados reportados por esta herramienta, parece que la velocidad de lectura de la tarjeta SD no es un problema. Así que puede ser la biblioteca HttpClient o algo más.
- Socket Android: java.net.SocketException: No hay ruta para alojar
- Conexiones de socket y Polling. ¿Cuál es la mejor solución en términos de duración de la batería?
- Implementación cliente / servidor de socket TCP de Android
- Cliente Android / socket de servidor Java; Android enviar pero no recibir?
- Android VpnService proteger socket que se almacena en código nativo?
- Envío de datos TCP desde Android (como cliente) - ¿no se envían datos?
- UDP Multicasting desde el móvil a la PC
- Conexión HTTP de Android
Sobrecarga en la conexión HTTP viene de los encabezados que envía junto con sus datos (que es básicamente una constante). Por lo tanto, cuanto más datos envíes, menos las cabeceras te harán daño. Sin embargo, el aspecto mucho más importante a considerar es la codificación .
Por ejemplo, si está enviando datos no ASCII, emparejado con un tipo mime de application/x-www-form-urlencoded
, corre el riesgo de explotar el tamaño de entrada porque los caracteres no ASCII deben escaparse.
De la especificación :
El tipo de contenido "application / x-www-form-urlencoded" es ineficiente para enviar grandes cantidades de datos binarios o texto que contengan caracteres no ASCII. El tipo de contenido "multipart / form-data" debe utilizarse para enviar formularios que contengan archivos, datos no ASCII y datos binarios.
La alternativa es multipart/form-data
que es eficiente para datos binarios. Por lo tanto, asegúrese de que su aplicación está utilizando este tipo MIME (incluso puede comprobar esto en los registros del servidor).
Otro método que puede reducir considerablemente su tiempo de carga es la compresión . Si está cargando datos que aún no están comprimidos (la mayoría de los formatos de imagen y vídeo ya están comprimidos) intente agregar compresión gzip a sus subidas. Otro post muestra los detalles de la configuración de esto en android.
Si sus datos son de un formato específico (por ejemplo, una imagen), puede buscar algoritmos de compresión sin pérdida para su tipo de datos (png para imágenes, FLAC para audio, etc.). La compresión siempre viene al precio de la CPU (batería), así que tenlo en cuenta.
Recuerda:
No optimice algo hasta que sepa que es el cuello de botella. Tal vez la conexión de su servidor es lenta, tal vez usted no puede leer desde el sistema de archivos de Android con la suficiente rapidez para empujar sus datos a la red. Ejecutar algunas pruebas y ver lo que funciona.
Si fuera yo, no implementaría el enfoque tcp recto. Sólo mis 2 centavos, buena suerte!
No, no hay ningún gasto significativo asociado con el uso de HTTP sobre sockets sin procesar. Sin embargo, realmente depende de cómo está utilizando HttpClient para enviar este archivo. ¿Está correctamente almacenando en búfer entre el sistema de archivos y HttpClient? La latencia podría no ser la red, sino leer el archivo desde el sistema de archivos. De hecho, aumentó la velocidad del enlace bruto en 3x y sólo vio una reducción de 2x. Eso probablemente significa que hay algún tipo de latencia en su código o en el servidor o sistema de archivos. Puede intentar cargar un archivo desde un cliente de escritorio para asegurarse de que no es el servidor que causa la latencia. Luego mira el sistema de archivos a través de put. Si todos los controles a cabo, a continuación, mira el código que ha escrito utilizando HttpClient y ver si se podría optimizar.
Observe también en CherryPy 3.2 que el sistema para manejar los cuerpos de solicitud ha sido completamente reelaborado, y usted es mucho más libre de implementar variados manejadores basados en el tipo de medio de la solicitud. Por defecto, CherryPy leerá los bytes cargados en un archivo temporal; Asumo que su código entonces copia eso a una localización más permanente, que pudo ser sobrecarga que no es útil a usted (aunque hay buenas razones de seguridad para utilizar un archivo temporal). Véase también esta pregunta para discutir el cambio de nombre de los archivos temporales.
Puede anular ese comportamiento ; haga una subclase de _cpreqbody.Part
con una función make_file
que haga lo que quiera, entonces, en una Herramienta, reemplace cherrypy.request.body.part_class
por ese URI. Luego publique su código en http://tools.cherrypy.org para que todos puedan beneficiarse 🙂
- Android: Añade escuchas de eventos a cada elemento de un ListView
- cómo devolver datos de AsyncTask al hilo principal