2011-05-05 21 views
5

He leído muchas publicaciones en este sitio sobre cómo recibir paquetes UDP en Android. Sin embargo, ¡nada de esto me funciona!Android UDP Comunicación

Algunos conceptos básicos:

estoy probando en mi HTC Incredible (Android 2.2) que se ejecutan en 3G (no wifi o cualquier otra cosa). No hay emuladores involucrados aquí.

Mi código es simple:

  1. Mi servidor (que funciona en mi PC) escucha el tráfico UDP en el puerto 8752.
  2. Mi aplicación Android abre una DatagramSocket en un puerto aleatorio y envía un paquete a mi servidor con este puerto.
  3. Guardo esta información (el InetAddress forma el paquete recibido y el puerto que se encuentra dentro del paquete).
  4. Intento enviar un paquete UDP desde mi servidor (nuevamente, en mi PC) a mi aplicación de Android (ejecutándose en mi teléfono) y NO funciona.
//Server code to initialize the UDP socket (snippet) 
public void init() { 
    datagram_server_socket = new DatagramSocket(port,local_addr); 
    datagram_server_socket.setSoTimeout(1000); 
} 

// fragmento de código en el Android APP que envía un paquete al servidor

public void connect() { 
    Random r = new Random(System.currentTimeMillis()); 
    int udp_port = 0; 
    while(true){ 
     try { 
      udp_port = r.nextInt(1000)+8000; 
      udp_port = 8000; 
      comm_skt = new DatagramSocket(udp_port); 
      Log.i("ServerWrapper", "UDP Listening on port: " + udp_port); 
      break; 
     } catch(SocketException e) { 
      Log.e("ServerWrapper", "Could not bind to port " + udp_port); 
     } 
    } 
    byte[] sdata = new byte[4+tid.length]; 
    i = 0; 
    sdata[i++] = (byte)(0XFF&(udp_port>>24)); 
    sdata[i++] = (byte)(0XFF&(udp_port>>16)); 
    sdata[i++] = (byte)(0XFF&(udp_port>>8)); 
    sdata[i++] = (byte)(0XFF&(udp_port)); 
    for(byte b: tid){ 
     sdata[i++] = b; 
    } 
    DatagramPacket pkt = new DatagramPacket(sdata, sdata.length, 
           InetAddress.getByName(hostname), port); 
    comm_skt.send(pkt); 
} 
//Server's UDP socket listening code 
public void serverUDPListener() { 
    try { 
     datagram_server_socket.receive(rpkt); 
     int port = 0; 
     byte[] rdata = rpkt.getData(); 
     port += rdata[0]<<24; 
     port += rdata[1]<<16; 
     port += rdata[2]<<8; 
     port += (0XFF)&rdata[3]; 
     byte[] tid = new byte[rdata.length]; 
     for(int i = 4; i < rdata.length && rdata[i] > 0; i++) { 
      tid[i-4] = rdata[i]; 
     } 
     String thread_id = new String(tid).trim(); 
     for(int i = 0; i < threads.size(); i++) { 
     ClientThread t = threads.get(i); 
     if(t.getThreadId().compareTo(thread_id) == 0) { 
      t.setCommSocket(rpkt, port); 
     } else { 
      System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND"); 
     } 
     } 
    } catch (IOException e) { 
     if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException)) 
     log.warning("Error while listening for an UDP Packet."); 
    } 
} 
//Corresponds to the setCommSocket call above to save the IP and Port of the incoming UDP packet on the server-end 
public void setCommSocket(DatagramPacket pkt, int port) { 
    comm_ip = pkt.getAddress(); 
    comm_port = pkt.getPort(); //Try the port from the packet? 
} 
//Sends an UDP packet from the SERVER to the ANDROID APP 
public void sendIdle() { 
    if(comm_ip != null) { 
     System.err.println("Sent IDLE Packet (" + comm_ip.getHostAddress() + ":" + comm_port + ")"); 
     DatagramPacket spkt = new DatagramPacket(new byte[]{1, ProtocolWrapper.IDLE}, 2, comm_ip, comm_port); 
     DatagramSocket skt; 
     try { 
      skt = new DatagramSocket(); 
      skt.send(spkt); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Ahora he duro codificado el puerto mi aplicación usa 8000. Sin embargo, lo extraño es que TODO EL TIEMPO pruebo mi programa (y veo la IP/Puerto que está guardado en mi servidor), el puerto del paquete procede de siempre es 33081. Tengo aa hilo escucha constante para el tráfico UDP en mi Android App pero el código no se ejecuta nunca superado la "recepción (paquetes)" parte:

public void AndroidUDPListener() { 
    while(true) { 
     synchronized(stop) { 
     if(stop) return; 
     } 
     byte[] recieve_data = new byte[64]; 
     DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length); 
     try { 
     if(comm_skt == null) 
       continue; 
     comm_skt.receive(rpkt); 
     byte[] data = rpkt.getData(); 
     switch(data[1]) { 
      case IDLE: 
      if(ocl != null) ocl.onCompletion(null); 
      break; 
      case KEEP_ALIVE: 
      break; 
     } 
     } catch (Exception e) { 
     if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException)) 
       Log.w("ServerWrapper", "Error while listening for an UDP Packet."); 
     } 
    } 
} 

¿Alguien ve un problema en mi código? ¿O hay algunos permisos/configuraciones que debo configurar primero en mi aplicación? Tengo habilitada la comunicación por internet.

Ejemplo de salida (a través del puerto del paquete getPort()):

Android App - Ahora escucha para el tráfico UDP en el puerto 8000

Android App - Envío de paquetes al servidor

Servidor - Paquete recibido de XXXXXX: 33081

Servidor - Envío de paquete IDLE a XXXXXX: 33081

Ejemplo de salida (a través del puerto de los datos del paquete):

Android App - Ahora escucha para el tráfico UDP en el puerto 8000

Android App - Envío de paquetes al servidor

Servidor - paquete recibido desde XXXXXX: 8000

servidor - Envío de paquetes IDLE para XXXXXX: 8000

La aplicación Android nunca recibe tráfico UDP de ninguno de los puertos.

+0

¿Se puede conseguir esto para el trabajo en dos computadoras de escritorio/portátiles (sin su teléfono Android)? Si puede eliminar el teléfono como problema, entonces podemos suponer que es un problema con su código. – Kiril

+0

Pude poner mi teléfono en mi red WiFi y obtener los paquetes UDP trabajando de esa manera (usando la dirección IP directa a mi máquina ya que el nombre de host, usando el nombre DNS externo NO funcionó). También hice que mi amigo probara un programa que escribí para simular las llamadas a la red de aplicaciones de Android en su casa (usando el nombre DNS externo) y funcionó bien (después de hacer un reenvío de puertos y forzar un puerto UDP no aleatorio). Espero que esto aclare que el problema es mi código. – someone1

Respuesta

3

Lo siento por no actualizar esto antes. El problema se solucionó de la siguiente manera:

Necesitaba almacenar el DatagramSocket en cada hilo. El socket de escucha también debe ser el socket utilizado para continuar la comunicación entre el servidor y el cliente. Aquí están los bits del código actualizado.

nuevo código de registro zócalo de hilo:

public void setCommSocket(DatagramPacket pkt, int port, DatagramSocket skt) 
{ 
    comm_ip = pkt.getAddress(); 
    comm_port = pkt.getPort(); 
    synchronized(comm_pkt) { 
    comm_pkt = pkt; 
    } 
    comm_skt = skt; 
} 

servidor nuevo Código Escuchando:

public void UDPListen() { 
     while(true) { 
      synchronized(stop) { 
       if(stop) 
        break; 
      } 

      byte[] recieve_data = new byte[64]; 
      DatagramPacket rpkt = new DatagramPacket(recieve_data, recieve_data.length); 
      try { 
       datagram_server_socket.receive(rpkt); 
       int port = 0; 
       byte[] rdata = rpkt.getData(); 
       port += rdata[0]<<24; 
       port += rdata[1]<<16; 
       port += rdata[2]<<8; 
       port += (0XFF)&rdata[3]; 
       byte[] tid = new byte[rdata.length]; 
       for(int i = 4; i < rdata.length && rdata[i] > 0; i++) 
       { 
        tid[i-4] = rdata[i]; 
       } 
       String thread_id = new String(tid).trim(); 
       for(int i = 0; i < threads.size(); i++) { 
        ClientThread t = threads.get(i); 
        if(t.getThreadId().compareTo(thread_id) == 0) 
        { 
         t.setCommSocket(rpkt, port, datagram_server_socket); 
        } else { 
         System.err.println("THREAD ID " + thread_id + " COULD NOT BE FOUND"); 
        } 
       } 
      } catch (IOException e) { 
       if(!(e instanceof SocketException) && !(e instanceof SocketTimeoutException)) 
        log.warning("Error while listening for an UDP Packet."); 
      } finally { 
       for(int i = 0; i < threads.size(); i++) { 
        ClientThread t = threads.get(i); 
        t.sendKeepAlive(); 
       } 
      } 
     } 
    } 

Hubo alguna actualización de la estructura del servidor/hilos que voy a Omitt. La parte importante aquí es que el socket en el que se recibió el paquete se volvió a usar para enviar datos al cliente.Además, se ha reutilizado el paquete de transmitir los datos de vuelta:

public void sendIdle() { 
     if(comm_ip != null) { 
      synchronized(comm_pkt) { 
       try { 
        comm_pkt.setData(new byte[]{1, ProtocolWrapper.IDLE}); 
        comm_skt.send(comm_pkt); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 
      } 
     } 

    } 

Aquí es las partes pertinentes de mi clase de contenedor que muestra lo que cada hilo sostenía:

public class PeerWrapper { 

    private InetAddress ipaddress; 
    private Integer port; 
    private Socket client_socket; 
    private InetAddress comm_ip; 
    private DatagramSocket comm_skt; 
    private DatagramPacket comm_pkt; 
    private int comm_port; 
    private byte status; 
2

Tuve un problema similar. En Android había dos enchufes (envío/escucha), y en un servidor de PC había dos tomas (envío/escucha). El teléfono haría ping a la toma de escucha conocida de la PC con la dirección de la toma de escucha desconocida del teléfono, para que la PC pueda responder. Nada de lo que estaba haciendo parecía estar obteniendo la dirección de la toma de audición, ya que el zócalo nunca recibiría nada.

Esto resolvió mi problema: Android: java.net.DatagramSocket.bind: Invalid Argument Exception. Use un canal para crear el socket y luego enlace en null. Ahora puedo usar el conector de envío en el teléfono para enviar un paquete que contiene el puerto de la toma de escucha (las IP son las mismas) a la PC, obtenido con .getLocalPort() La PC lee el byte [], obtiene el puerto y envía paquetes de vuelta al puerto de escucha de los teléfonos.

+0

Hola, gracias por tu respuesta. No estoy 100% seguro de que hubiera solucionado mi problema, pero terminé este proyecto (y resolví mi problema) hace más de un año y no tengo tiempo para probar si esto funciona. – someone1

1

Android tienen cortafuegos entrante

usted tiene que utilizar primero UDOP perforadora mismo objeto calcetín con temporizador

Cuestiones relacionadas