2015-09-04 16 views
5

Attualmente sto cercando di implementare la punzonatura di udp su Android per il mio server udp. Le cose dovrebbero funzionare in questo modo:Punzonatura fori UDP su Android; Server UDP

  1. Il cliente (dietro un NAT, forse 3G, ..) invia un DatagramPacket al server (il server ha un IP pubblico; porta è noto anche per essere 45555). Il client si ripete per inviare un datagramma con un determinato ritardo
  2. Una volta che il server ha ricevuto un datagramma, invia i datagrammi ("segnali") ogni 500ms.
  3. Se perforazione lavorato, il cliente deve ricevere i segnali

Ecco il mio attuale implementazione client (Android):

//in onCreate() 
    DatagramSocket socket = new DatagramSocket(46222); 
    socket.setSoTimeout(2000); 
    final Thread t = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      int delay = Integer.parseInt(e2.getText().toString());//e1 and e2 are EditTexts 
      String ip = e1.getText().toString(); 
      try { 
       DatagramPacket packet = new DatagramPacket(new byte[1],1, InetAddress.getByName(ip), 45555); 
       while(!cleanUp){//cleanUp is set to true in onPause() 
        lock.lock(); //Lock lock = new ReentrantLock(); 
        socket.send(packet); 
        lock.unlock(); 
        Thread.sleep(delay); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      }finally{ 
       if(socket!=null) 
        socket.close(); 
      } 
     } 

    }); 
    final Thread t2 = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      try { 
       Thread.sleep(1000); 
       DatagramPacket packet = new DatagramPacket(new byte[1],1); 
       while(!cleanUp){ 
        lock.lock(); 
        try{ 
         socket.receive(packet); 
        }catch(SocketTimeoutException e){ 
         lock.unlock(); 
         Thread.sleep(15); 
         continue; 
        } 
        lock.unlock(); 
        final String s = tv.getText().toString()+"signal\n"; 
        MainActivity.this.runOnUiThread(new Runnable(){ 

         @Override 
         public void run() { 
          tv.setText(s);//tv is a TextView 
         } 

        }); 
        Thread.sleep(10); 
       } 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
      finally{ 
       if(socket!=null) 
        socket.close(); 
      } 
     } 

    }); 
    //start both threads 

Qui è l'implementazione lato server (Java):

//int static void main(String[] args): 
final Thread t = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      try { 
       DatagramPacket packet = new DatagramPacket(new byte[1],1, addr, port); 
       DatagramSocket socket = new DatagramSocket(); 
       System.out.println("send"); 
       while(true){ 
        socket.send(packet); 
        Thread.sleep(500); 
       } 
      } catch (Exception e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

    }); 
    final Thread t2 = new Thread(new Runnable(){ 

     @Override 
     public void run() { 
      try { 
       DatagramPacket packet = new DatagramPacket(new byte[1],1); 
       DatagramSocket socket = new DatagramSocket(45555); 
       socket.receive(packet); 
       addr = packet.getAddress(); //private static field InetAddress addr 
       port = packet.getPort(); 
       System.out.println(addr+":"+ packet.getPort()); //field int port 
       t.start(); 
       while(true){ 
        socket.receive(packet); 
        System.out.println("idle"); 
       } 
      } catch (Exception e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 
     } 

    }); 
    t2.start(); 

Tutto funziona quando client e server si trovano nella stessa rete privata. Per imitare il server pubblico eseguo il codice lato server sul mio computer e configuro una porta sul mio router (che ha un ip pubblico) *. I client invieranno i propri pacchetti all'IP pubblico del router. Ma in entrambi i casi (il mio smartphone è connesso ad internet tramite la mia rete wlan/3G o E) non vengono ricevuti segnali (il server riceve i datagrammi del client)

Quindi perché il processo di perforazione non funziona?

riguarda

*: Il router inoltrerà i pacchetti UDP inviati al suo porto 45555 al mio computer

+0

Cosa intendi per "configurare una porta sul mio router"? E quello che stai facendo non è perforare. La perforatura viene utilizzata per stabilire una connessione peer-to-peer tra due client dietro NAT diversi. – Tahlil

+1

Il router inoltrerà tutti i pacchetti udp inviati alla sua porta 45555 al mio computer – user2224350

risposta

3

diverse prese si lega ad un'altra porta privata e utilizzare un'altra porta pubblica del vostro NAT. Stai ricevendo e inviando attraverso diverse prese. Invia con lo stesso socket attraverso il quale hai ricevuto i dati. Altrimenti Il socket di invio utilizza una diversa porta pubblica del router per inviare dati ai client NAT. Questo pacchetto scarta gli scarti NAT dei client perché provengono dallo stesso IP ma dalla porta sconosciuta.

+0

Thx che dovrebbe essere il problema. Ma sul lato server voglio ricevere e inviare datagramma contemporaneamente. Esiste un modo per inviare e ricevere datagrammi sullo stesso socket (o con la stessa porta) simultaneamente in Java – user2224350

+1

I socket sono bidirezionali, quindi è possibile inviare e ricevere dati contemporaneamente. Ma potresti voler gestire il caso in cui un thread chiude bruscamente il socket. – Tahlil