2017-07-13 2 views
0

Je travaille sur une application de téléphone Android (H) qui parle à un pair, un RPi 3 (P), via UDP hole-punching. J'ai deux sockets (s et s_vid) sur H qui seront tous deux perforés grâce à un serveur maître (M), et un socket (S3 pour plus de clarté, mais 's' dans le code) sur P. H est sur le réseau mobile, P sur ma connexion Wi-Fi et M sur Google Cloud Engine.Android UDP trou-poinçonnage échoue sur deuxième socket (Python + Java)

Déroulement du programme:


H utilise s ping M, M envoie adr/informations port à P.

H utilise s_vid ping M, M envoie adr/informations port à P.

P utilise S3 ping M, M envoie adr/informations port à H.

(nous devrions maintenant être perforé trou-)

H utilise s pour envoyer des paquets périodiques à P sur le port de S3.

P utilise S3 pour envoyer des paquets périodiques à H sur le port s.

(tout cela fonctionne très bien sans problème ... ci-dessous ne fonctionne pas)

P utilise S3 pour envoyer des paquets périodiques à H sur le port de s_vid. (ou, plutôt, il devrait).


Nous devrions avoir 3 flux de paquets: H @ s -> P @ S3, P @ S3 -> H @ s et P @ S3 -> H @ s_vid, mais pour une raison que la première deux travaux. Le dernier se bloque sur la ligne s_vid.receive() (voir code).

Voici le code (correspondant) H:

public class MainActivity extends AppCompatActivity implements SurfaceHolder.Callback, MediaPlayer.OnPreparedListener, SensorEventListener{ 

    public String messageStr; 
    public String masterMessageStr; 
    public int master_msg_length; 
    public int msg_length; 
    public String masterMessageVidStr; 
    public int master_msg_vid_length; 

    public DatagramPacket p_peer; 
    public DatagramPacket p_master; 
    public DatagramPacket p_master_vid; 
    public DatagramPacket p_rec; 
    public DatagramPacket p_rec_vid; 
    public DatagramSocket s; 
    public DatagramSocket s_vid; 

    public InetAddress return_peer_addr; 
    public int return_peer_port; 
    public InetAddress master_addr; 
    public int master_port; 


    @Override 
    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     setContentView(R.layout.activity_main); 

    } 

    @Override 
    public void onStart() { 
     super.onStart(); 
    } 

    @Override 
    public void onStop() { 
     super.onStop(); 
    } 

    @Override 
    protected void onResume() { 
     super.onResume(); 

     //Define Sockets 
     try { 
      s = new DatagramSocket(); 
      s.setReuseAddress(true); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
     try { 
      s_vid = new DatagramSocket(); 
      s_vid.setReuseAddress(true); 
     } 
     catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 

     try { 
      master_addr = InetAddress.getByName("xx.xxx.xxx.xxx");//hardcoded server address 
     } catch (Exception e) 
     { 
      e.printStackTrace(); 
     } 
     master_port = 1111;//hardcoded server port 


     //listen for server or peer packets. 
     Runnable receive_thread_run = new Runnable() { 
      @Override 
      public void run() { 
       while(true){ 
        byte[] buf = new byte[1024]; 
        p_rec = new DatagramPacket(buf,buf.length); 
        try { 
         s.receive(p_rec); 

         //Do stuff... 
         //this works fine. 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }; 

     //listen for peer packets. PROBLEM IS HERE. 
     Runnable receive_thread_run_vid = new Runnable() { 
      @Override 
      public void run() { 

       byte[] buf_vid = new byte[1024]; 
       p_rec_vid = new DatagramPacket(buf_vid,buf_vid.length); 

       try { 
        s_vid.receive(p_rec_vid);//this is reached, but never receives... 

        //Do stuff...never reached. 

       } 
       catch (Exception e) 
       { 
        e.printStackTrace(); 
       } 
      } 
     }; 

     //Start the threads 
     Thread receive_thread_vid = new Thread(receive_thread_run_vid); 
     receive_thread_vid.start(); 

     Thread receive_thread = new Thread(receive_thread_run); 
     receive_thread.start(); 

     //Send out pings to master server for hole-punching. 
     TimerTask return_master = new TimerTask(){ 
      @Override 
      public void run() { 

       masterMessageStr = "someping"; 

       master_msg_length = masterMessageStr.length(); 
       byte[] msg = masterMessageStr.getBytes(); 

       p_master = new DatagramPacket(msg,master_msg_length,master_addr,master_port); 

       try { 
        s.send(p_master); 
       } 
       catch (Exception e) 
       { 
        e.printStackTrace(); 
       } 

      } 
     }; 

     Timer return_master_timer = new Timer(); 
     return_master_timer.scheduleAtFixedRate(return_master,1000,1000); 

     //Send out pings to master server for hole-punching (2nd socket). 
     TimerTask return_master_vid = new TimerTask(){ 
      @Override 
      public void run() { 

       masterMessageVidStr = "someotherping"; 

       master_msg_vid_length = masterMessageVidStr.length(); 
       byte[] msg_vid = masterMessageVidStr.getBytes(); 

       p_master_vid = new DatagramPacket(msg_vid,master_msg_vid_length,master_addr,master_port); 

       try { 
        s_vid.send(p_master_vid); 
       } 
       catch (Exception e) 
       { 
        e.printStackTrace(); 
       } 

      } 
     }; 

     Timer return_master_timer_vid = new Timer(); 
     return_master_timer_vid.scheduleAtFixedRate(return_master_vid,1000,1000); 

     //Talk directly to the peer. 
     TimerTask return_peer = new TimerTask(){ 
      @Override 
      public void run() { 

       //Do stuff... 

       messageStr = "some peer-directed message"; 

       msg_length = messageStr.length(); 
       byte[] msg = messageStr.getBytes(); 

       p_peer = new DatagramPacket(msg,msg_length,return_peer_addr,return_peer_port); 

       //check we know where to send it 
       if (return_peer_addr != null && return_peer_port != 0) { 
        try { 
         s.send(p_peer); 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }; 

     Timer return_peer_timer = new Timer(); 
     return_peer_timer.scheduleAtFixedRate(return_peer,500,500);//time in milliseconds 
    } 
} 

Voici le code (correspondant) M:

import socket 
import sys 
import time 
import threading 

## peer-Master UDP Comms 
def receive_peer():#gets peer addr and sends it to phone. 
    global peer_addr 
    global peer_port 

    while 1: 
     data, addr = s_peer.recvfrom(1024) 

     #figure out who is talking (should only be peer) 
     if data == 'somepeerping': 
      peer_addr = addr[0] 
      peer_port = addr[1] 

      #send it to phone 
      if phone_addr is not None and peer_addr is not None and peer_port is not None: 
       phone_ret_data = '{\"return_addr\":\"'+peer_addr+'\",\"return_port\":\"'+str(peer_port)+'\"}' 
       s_phone.sendto(phone_ret_data,(phone_addr,phone_port)) 

## Phone-Master UDP Comms 
def receive_phone():#gets phone addr (and phone vid addr) and sends it to peer. 
    global phone_addr 
    global phone_port 
    global phone_addr_vid 
    global phone_port_vid 
    global peer_ret_data 
    global peer_ret_data_vid 

    while 1: 
     data, addr = s_phone.recvfrom(1024) 

     #figure out who is talking (whih of the two sockets) 
     if data == 'someping': 
      phone_addr = addr[0] 
      phone_port = addr[1] 

      if peer_addr is not None and phone_addr is not None and phone_port is not None: 
       peer_ret_data = '{\"return_addr\":\"'+phone_addr+'\",\"msg_type\":\"novid\",\"return_port\":\"'+str(phone_port)+'\"}' 
       s_peer.sendto(peer_ret_data,(peer_addr,peer_port)) 
     elif data == 'someotherping': 
      phone_addr_vid = addr[0] 
      phone_port_vid = addr[1] 

      if peer_addr is not None and phone_addr_vid is not None and phone_port_vid is not None: 
       peer_ret_data_vid = '{\"return_addr\":\"'+phone_addr_vid+'\",\"msg_type\":\"vid\",\"return_port\":\"'+str(phone_port_vid)+'\"}' 
       s_peer.sendto(peer_ret_data_vid,(peer_addr,peer_port)) 

HOST = '' 
PORT_peer = 2222 
PORT_phone = 1111 

peer_addr = None 
peer_port = None 
phone_addr = None 
phone_port = None 
phone_addr_vid = None 
phone_port_vid = None 

peer_ret_data = None 
peer_ret_data_vid = None 
phone_ret_data = None 

## peer socket 
try: 
    s_peer = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    s_peer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    print("Socket created.") 
except socket.error, msg: 
    print("Failed. Error: " + str(msg)) 
    sys.exit() 

try: 
    s_peer.bind((HOST,PORT_peer)) 
    print("Socket binding complete.") 
except socket.error, msg: 
    print("Bind failed. Error: " + str(msg)) 
    s_peer.close() 
    sys.exit() 

## Phone socket 
try: 
    s_phone = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    s_phone.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    print("Socket created.") 
except socket.error, msg: 
    print("Failed. Error: " + str(msg)) 
    sys.exit() 

try: 
    s_phone.bind((HOST,PORT_phone)) 
    print("Socket binding complete.") 
except socket.error, msg: 
    print("Bind failed. Error: " + str(msg)) 
    s_phone.close() 
    sys.exit() 


## Initiate threads 
threading.Thread(target=receive_peer).start() 
threading.Thread(target=receive_phone).start() 

Voici le code (correspondant) P:

import socket 
import sys 
import time 
import threading 
import json 
import time 
import subprocess 

## UDP Comms - thread to receive incoming packets. 
def receive_thread(): 
    global master_addr 
    global master_port 
    global return_phone_addr 
    global return_phone_port 
    global return_phone_vid_addr 
    global return_phone_vid_port 
    global phone_packet_count 

    while 1: 
     data, addr = s.recvfrom(1024) 

     if addr[0] == master_addr and addr[1] == master_port:#message from master server, update return addresses 
      master_msg_received = json.loads(data) 
      master_msg_received = {str(key):str(value) for key,value in master_msg_received.items()}#to remove unicode 

      if master_msg_received['msg_type'] == 'novid': 
       return_phone_addr = master_msg_received['return_addr'] 
       return_phone_port = int(master_msg_received['return_port']) 
      elif master_msg_received['msg_type'] == 'vid': 
       return_phone_vid_addr = master_msg_received['return_addr'] 
       return_phone_vid_port = int(master_msg_received['return_port']) 
     elif addr[0] == return_phone_addr and addr[1] == return_phone_port and return_phone_addr is not None:#message from phone 
      phone_packet_count = phone_packet_count + 1 
      msg_received = json.loads(data) 
      msg_received = json.dumps(msg_received)#to remove unicode 

      #Do stuff...no problems here or above. 


## UDP Comms - threads to send out packets. 
#send our address to master. 
def ping_master(): 
    global master_addr 
    global master_port 

    s.sendto('somepeerping',(master_addr,master_port)) 
    threading.Timer(1,ping_master).start() 

#return data to phone (for now packet count). 
def return_phone(): 
    global return_phone_addr 
    global return_phone_port 
    global phone_packet_count 

    if return_phone_addr is not None: 
     s.sendto(str(phone_packet_count),(return_phone_addr,return_phone_port)) 

    threading.Timer(0.5,return_phone).start() 

#send other data to phone on its second socket. POSSIBLE PROBLEM. 
def return_phone_vid(): 
    global return_phone_addr 
    global return_phone_port 
    global return_phone_vid_addr 
    global return_phone_vid_port 

    if return_phone_vid_addr is None: 
     threading.Timer(0.7,return_phone_vid).start() 
    else: 
     s.sendto('some second socket test ping',(return_phone_vid_addr,return_phone_vid_port)) 
     threading.Timer(0.7,return_phone_vid).start() 


HOST = '' 
PORT_phone = 0 #this is where phone comms arrive. 

phone_packet_count = 0 
return_phone_addr = None #this is where phone comms go. 
return_phone_port = None #this is where phone comms go. 
return_phone_vid_addr = None #this is where phone comms go. 
return_phone_vid_port = None #this is where phone comms go. 

master_addr = 'xx.xxx.xxx.xxx'#this is where master comms go. hardcoded. 
master_port = 2222#this is where master comms go. 
PORT_master = 0 #this is where master comms arrive. 

## UDP Comms - initialize sockets. 
try: 
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 
    print("Socket created.") 
except socket.error, msg: 
    print("Failed. Error: " + str(msg)) 
    sys.exit() 

try: 
    s.bind((HOST,PORT_phone)) 
    print("Socket binding complete.") 
except socket.error, msg: 
    print("Bind failed. Error: " + str(msg)) 
    s.close() 
    sys.exit() 

## Initiate threads 
threading.Thread(target=receive_thread).start() 
ping_master() 
return_phone() 
return_phone_vid() 

Des idées sur ce qui pourrait en être la cause? J'ai déjà confirmé que P reçoit 2 ports différents (même adresse) pour s et s_vid. Je m'attendrais à ce que les deux sockets échouent ou pas, pas seulement un. Peut-être un problème de pare-feu? Mais encore une fois, pourquoi une seule socket échoue? Merci pour l'aide!

Répondre

0

C'était une erreur de perforation de ma part. Les prises perforées doivent se parler directement.Donc, dans le style de ma question, j'avais:

P @ S3 -> H @ s_vid mais pas H @ s_vid -> P @ S3 (j'avais les deux sens sur l'autre socket). Le correctif ajoute cette direction à l'application de téléphone, semblable à

TimerTask return_peer_vid = new TimerTask(){ 
      @Override 
      public void run() { 

       retMessageVidStr = "test"; 

       ret_msg_vid_length = retMessageVidStr.length(); 
       byte[] msg = retMessageVidStr.getBytes(); 

       p_peer_vid = new DatagramPacket(msg,ret_msg_vid_length,return_peer_addr,return_peer_port); 

       //check we know where to send it 
       if (return_peer_addr != null && return_peer_port != 0) { 
        try { 
         s_vid.send(p_peer_vid); 
        } 
        catch (Exception e) 
        { 
         e.printStackTrace(); 
        } 
       } 
      } 
     }; 

     Timer return_peer_timer_vid = new Timer(); 
     return_peer_timer_vid.scheduleAtFixedRate(return_peer_vid,500,500);//time in milliseconds