2011-07-03 16 views
6

Me gustaría reducir el tiempo de keepalive TCP en un socket que estoy abriendo desde 2 horas a algo del orden de diez minutos. Puedo hacer que use keepalive con socket.setKeepAlive (true), pero ¿cómo puedo controlar el tiempo antes de que se envíe un paquete keepalive?Cómo configurar el tiempo de espera de keepalive en Android?

Parece que podría hacer esto si estuviera usando el NDK, pero quiero distribuir este código como un contenedor, por lo que no es ideal para mí.

Respuesta

1

Probablemente esta sea una respuesta demasiado obvia [es decir no es una opción para su caso específico] pero puede, por supuesto, implementar su propio keepalive enviando 1 byte desprendible (en cualquier dirección) cada 10 minutos.

+0

Sí, probablemente termine haciendo eso. Sin embargo, he oído que es más exigente con la duración de la batería. Puedo configurar el keepalive del lado del servidor que, con suerte, es razonable. – lacker

4

Android está basado en Linux y Linux soporta las TCP_KEEPIDLE y TCP_KEEPINTVL opciones de conector a través de la función setsocketopt(), que se envuelve por la interfaz java.net.SocketOptions. java.net.SocketImpl implementa SocketOptions y java.net.Socket envuelve un SocketImpl. Lo que no sé es si es posible acceder al SocketImpl de un objeto dado Socket.

Lo que se podría tratar de hacer es usar Socket.setSocketImplFactory() para implementar su propia clase personalizada SocketImplFactory, que es responsable de la creación de instancias de SocketImplSocket objetos. De esta forma, su fábrica puede llamar al SocketOptions.setOption() para TCP_KEEPIDLE y TCP_KEEPINTVL para cualquier sockets que cree su aplicación.

+0

+1 para obtener información sobre el uso de TCP_KEEPIDLE y TCP_KEEPINTVL en el caso de Android. Pero [esto] (http://stackoverflow.com/a/1480246/3574669) está votando por la implementación del nivel de aplicación no del nivel de sistema keepalive. ¿Cuál es su opinión? – ajay

+0

Esta pregunta era específicamente sobre keepalive a nivel de sistema, que todas las plataformas admiten ya que es parte del sec de TCP (aunque no todas las plataformas admiten establecer el intervalo). El keepalive del nivel de aplicación depende del protocolo, y muchos protocolos no admiten un keepalive a nivel de aplicación. ** SI ** es posible utilizar keepalive a nivel de aplicación, utilícelo. Pero vuelve a keepalive a nivel del sistema cuando sea necesario. –

8

Yo creo que puede ser bastante importante para poder establecer el keepalive tiempos de espera en una por nivel de aplicación, sobre todo en un dispositivo móvil, ya que podría estar bajo condiciones de red malo (wifi/móvil) . Si la aplicación no envía (m) ningún dato pero usa una conexión persistente, el socket no detectará si la conexión se pierde, a menos que envíe tcp sondas keepalive. La configuración de esta opción generalmente es posible a través de la llamada setsockopt(2), pero la sdk de Android proporciona solo la opción setKeepAlive(boolean). Más profundo en la pila, que funciona llamadas libcore.io.ForwardingOs.setsockoptInt(...), que es no disponible directamente, ni el descriptor de archivo requerido. Al usar la reflexión de java, es posible establecer los tiempos de espera de keepalive de todos modos, e.g como esto:

private final static int SOL_TCP = 6; 

private final static int TCP_KEEPIDLE = 4; 
private final static int TCP_KEEPINTVL = 5; 
private final static int TCP_KEEPCNT = 6; 

protected void setKeepaliveSocketOptions(Socket socket, int idleTimeout, int interval, int count) { 
    try { 
    socket.setKeepAlive(true); 
    try { 
     Field socketImplField = Class.forName("java.net.Socket").getDeclaredField("impl"); 
     socketImplField.setAccessible(true); 
     if(socketImplField != null) { 
     Object plainSocketImpl = socketImplField.get(socket); 
     Field fileDescriptorField = Class.forName("java.net.SocketImpl").getDeclaredField("fd"); 
     if(fileDescriptorField != null) { 
      fileDescriptorField.setAccessible(true); 
      FileDescriptor fileDescriptor = (FileDescriptor)fileDescriptorField.get(plainSocketImpl); 
      Class libCoreClass = Class.forName("libcore.io.Libcore"); 
      Field osField = libCoreClass.getDeclaredField("os"); 
      osField.setAccessible(true); 
      Object libcoreOs = osField.get(libCoreClass); 
      Method setSocketOptsMethod = Class.forName("libcore.io.ForwardingOs").getDeclaredMethod("setsockoptInt", FileDescriptor.class, int.class, int.class, int.class); 
      if(setSocketOptsMethod != null) { 
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPIDLE, idleTimeout); 
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPINTVL, interval); 
      setSocketOptsMethod.invoke(libcoreOs, fileDescriptor, SOL_TCP, TCP_KEEPCNT, count); 
      } 
     } 
     } 
    } 
    catch (Exception reflectionException) {} 
    } catch (SocketException e) {} 
} 

Esto funciona al menos hasta la siguiente se cumplen los requisitos:

  • libcore.io.ForwardingOs.setsockoptInt/4 existe en la versión actual SDK
  • java.net.Socket tiene un miembro de impl en el versión sdk actual
  • java.net.Socket->impl es instancia de java.net.SocketImpl en la versión actual SDK
  • java.net.SocketImpl ha un miembro de fd en la versión actual SDK
  • TCP_KEEPIDLE, TCP_KEEPINTVL y TCP_KEEPCNT tienen los mismos valores (4, 5 y 6) en la versión actual SDK y todos los dispositivos/arquitecturas de Android.

Eso parece ser cierto al menos para las versiones de Android de4.0.1/November 2011 hasta reciente versión5.1.1 r9.

Ver luni/src/main/java/libcore/io/Os.java, luni/src/main/java/java/net/Socket.java y luni/src/main/java/java/net/SocketImpl.java desde el repositorio platform/libcore. TCP_KEEPIDLE, TCP_KEEPINTVL y TCP_KEEPCNT parecen tener los mismos valores para las versiones de Android desde 2.2.3 r2 y todas las arquitecturas. Esto puede ser validado, p. ejecutando find . -name tcp.h | xargs grep -ho "TCP_KEEP\w\+\s\+\d\+" | sort | uniq -c en el repositorio android platform/ndk.

+0

erm ... Tan simple como eso, supongo ... – Bharel

Cuestiones relacionadas