2013-04-01 11 views
7

zu empfangen Ich versuche, eine sehr einfache SSDP-Funktionalität in meine Android-App from here zu implementieren.Nicht in der Lage, richtige UDP-Pakete mit SSDP

Meine Anwendung sendet einige UDP-Pakete, die eine relevante M-SEARCH-Nachricht enthalten, ohne Probleme an die Sendeadresse. Das Problem ist, dass ich von anderen Geräten, auf denen ein UPNP-Server läuft, eine korrekte Antwort erhalten sollte. Aus irgendeinem Grund erhalte ich nur genau die gleichen Pakete, die ich von meinem Android-Gerät gesendet habe.

MainActivity.java

@Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 

     WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE); 
     WifiManager.MulticastLock multicastLock = wm.createMulticastLock("multicastLock"); 
     multicastLock.setReferenceCounted(true); 
     multicastLock.acquire(); 

     setContentView(R.layout.activity_main); 

     ((Button)this.findViewById(R.id.btnSendSSDPSearch)).setOnClickListener(this); 
    } 

@Override 
    public void onClick(View v) { 
     switch (v.getId()) { 
     case R.id.btnSendSSDPSearch: 
      new Thread(new Runnable() { 

       @Override 
       public void run() { 
        SendMSearchMessage(); 
       } 
      }).start(); 

     default: 
      break; 
     } 
    } 

private void SendMSearchMessage() { 

       SSDPSearchMsg searchContentDirectory = new SSDPSearchMsg(SSDPConstants.ST_ContentDirectory); 
    SSDPSearchMsg searchAVTransport = new SSDPSearchMsg(SSDPConstants.ST_AVTransport); 
    SSDPSearchMsg searchProduct = new SSDPSearchMsg(SSDPConstants.ST_Product); 

    SSDPSocket sock; 
    try { 
     sock = new SSDPSocket(); 
     for (int i = 0; i < 2; i++) { 
      sock.send(searchContentDirectory.toString()); 
      sock.send(searchAVTransport.toString()); 
      sock.send(searchProduct.toString()); 
     } 

     while (true) { 
      DatagramPacket dp = sock.receive(); //Here, I only receive the same packets I initially sent above 
      String c = new String(dp.getData()); 
      System.out.println(c); 
     } 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     Log.e("M-SEARCH", e.getMessage()); 

    } 

SSDPSocket.java wo die UDP-Paket Übertragung tatsächlich

public class SSDPSocket { 
    SocketAddress mSSDPMulticastGroup; 
    MulticastSocket mSSDPSocket; 
    InetAddress broadcastAddress; 

    public SSDPSocket() throws IOException { 
     mSSDPSocket = new MulticastSocket(55325); //Bind some random port for receiving datagram 
     broadcastAddress = InetAddress.getByName(SSDPConstants.ADDRESS); 
     mSSDPSocket.joinGroup(broadcastAddress); 
    } 

    /* Used to send SSDP packet */ 
    public void send(String data) throws IOException { 
     DatagramPacket dp = new DatagramPacket(data.getBytes(), data.length(), 
       broadcastAddress,SSDPConstants.PORT); 

     mSSDPSocket.send(dp); 
    } 

    /* Used to receive SSDP packet */ 
    public DatagramPacket receive() throws IOException { 
     byte[] buf = new byte[1024]; 
     DatagramPacket dp = new DatagramPacket(buf, buf.length); 

     mSSDPSocket.receive(dp); 

     return dp; 
    } 

    public void close() { 
     if (mSSDPSocket != null) { 
      mSSDPSocket.close(); 
     } 
    } 
} 

SSDPSearchMsg.java für den Aufbau SSDP Broadcast-String (wahrscheinlich in keinem Zusammenhang mit dem Problem, das ich bin fertig ist Erleben, aber nur für den Fall)

public class SSDPSearchMsg { 
    static final String HOST = "Host:" + SSDP.ADDRESS + ":" + SSDP.PORT; 
    static final String MAN = "Man:ssdp:discover"; 
    static final String NEWLINE = System.getProperty("line.separator"); 

    int mMX = 3; /* seconds to delay response */ 
    String mST;  /* Search target */ 

    public SSDPSearchMsg(String ST) { 
     mST = ST; 
    } 

    public int getmMX() { 
     return mMX; 
    } 

    public void setmMX(int mMX) { 
     this.mMX = mMX; 
    } 

    public String getmST() { 
     return mST; 
    } 

    public void setmST(String mST) { 
     this.mST = mST; 
    } 

    @Override 
    public String toString() { 
     StringBuilder content = new StringBuilder(); 

     content.append(SSDP.SL_MSEARCH).append(NEWLINE); 
     content.append(HOST).append(NEWLINE); 
     content.append(MAN).append(NEWLINE); 
     content.append(mST).append(NEWLINE); 
     content.append("MX:" + mMX).append(NEWLINE); 
     content.append(NEWLINE); 

     return content.toString(); 
    } 
} 

SSDPConstants.java

public class SSDPConstants { 
    /* New line definition */ 
    public static final String NEWLINE = "\r\n"; 

    public static final String ADDRESS = "239.255.255.250"; 
    public static final int PORT = 1900; 

    /* Definitions of start line */ 
    public static final String SL_NOTIFY = "NOTIFY * HTTP/1.1"; 
    public static final String SL_MSEARCH = "M-SEARCH * HTTP/1.1"; 
    public static final String SL_OK = "HTTP/1.1 200 OK"; 

    /* Definitions of search targets */ 
    public static final String ST_RootDevice = "St: rootdevice"; 
    public static final String ST_ContentDirectory = "St: urn:schemas-upnp-org:service:ContentDirectory:1"; 
    public static final String ST_AVTransport = "St: urn:schemas-upnp-org:service:AVTransport:1"; 
    public static final String ST_Product = "St: urn:av-openhome-org:service:Product:1"; 

    /* Definitions of notification sub type */ 
    public static final String NTS_ALIVE = "NTS:ssdp:alive"; 
    public static final String NTS_BYE = "NTS:ssdp:byebye"; 
    public static final String NTS_UPDATE = "NTS:ssdp:update"; 
} 

habe ich auch sicher, dass das Manifest relevanten Berechtigungen beinhaltet:

<uses-permission android:name="android.permission.INTERNET"/> 
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" /> 
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> 
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> 

Ich teste die App auf einem Gerät, nicht auf Emulator.

Jede Hilfe wäre willkommen.

Bearbeiten auf Kommentar:

Multicast selbst sollte ohne Probleme funktionieren. Ich habe eine App namens BubbleUPNP heruntergeladen, um die SSDP-Funktionalität zu testen. Sicher genug, fängt wireshark richtig alle Nachrichten vom Telefon auf die Verbreitungsadresse in SSDP-Protokoll gesendet:

M-SEARCH * HTTP/1.1 

Man: "ssdp:discover" 

Mx: 3 

Host: 239.255.255.250:1900 

St: urn:schemas-upnp-org:service:AVTransport:1 

Und die Antwort

HTTP/1.1 200 OK 

ST:urn:schemas-upnp-org:service:ContentDirectory:1 

USN:uuid:d5829e90-73ce-4213-9ad1-4e75dbdd0232::urn:schemas-upnp-org:service:ContentDirectory:1 

Location:http://10.175.95.4:2869/upnphost/udhisapi.dll?content=uuid:d5829e90-73ce-4213-9ad1-4e75dbdd0232 

OPT:"http://schemas.upnp.org/upnp/1/0/"; ns=01 

01-NLS:05f3dd08b4b4b5aafa1fe983fa447f49 

Cache-Control:max-age=900 

Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 

Also ja, dies ist ohne Zweifel, ein Implementierungsproblem. Nichts ist falsch mit dem Gerät.

+0

Nur eine Seite: der beste WireShark - Filter, den ich gefunden habe, nur die SSDP - Pakete zu sehen ist: ** (udp enthält "HTTP/1.1") und ((udp enthält 0a: 53: 54: 3a) oder (udp enthält 0a: 59: 54: 3a)) ** Das Hex ist "ST:" und "NT:" am Anfang der Zeile. –

Antwort

4

Seltsam. Ich habe das Problem behoben, aber ich bin mir wirklich nicht sicher, wie es funktioniert hat.

Hier einige Änderungen, die ich gemacht:

Statt einen festen Port zuzuweisen, habe ich es dynamisch einen verfügbaren Port zuweisen.

public class SSDPSocket { 
    SocketAddress mSSDPMulticastGroup; 
    MulticastSocket mSSDPSocket; 
    InetAddress broadcastAddress; 

    public SSDPSocket() throws IOException { 

     mSSDPSocket = new MulticastSocket(); 
     broadcastAddress = InetAddress.getByName(SSDPConstants.ADDRESS); 
     mSSDPSocket.joinGroup(broadcastAddress); 
    } 
... 
} 

Ich änderte auch die M-Search-Nachrichtenstruktur, einschließlich der Reihenfolge.

public class SSDPSearchMsg { 
    static final String HOST = "Host: " + SSDPConstants.ADDRESS + ":" + SSDPConstants.PORT; 
    static final String MAN = "Man: \"ssdp:discover\""; 
    static final String NEWLINE = "\r\n"; 

    int mMX = 3; /* seconds to delay response */ 
    String mST;  /* Search target */ 

    public SSDPSearchMsg(String ST) { 
     mST = ST; 
    } 

    public int getmMX() { 
     return mMX; 
    } 

    public void setmMX(int mMX) { 
     this.mMX = mMX; 
    } 

    public String getmST() { 
     return mST; 
    } 

    public void setmST(String mST) { 
     this.mST = mST; 
    } 

    @Override 
    public String toString() { 
     StringBuilder content = new StringBuilder(); 

     content.append(SSDPConstants.SL_MSEARCH).append(NEWLINE); 
     content.append(MAN).append(NEWLINE); 
     content.append("Mx: " + mMX).append(NEWLINE); 
     content.append(HOST).append(NEWLINE); 
     content.append(mST).append(NEWLINE); 
     content.append(NEWLINE); 

     return content.toString(); 
    } 
} 

Und alles funktioniert plötzlich. Warum es funktioniert, ist jenseits von mir. Meine vorherige Implementierung folgt dem SSDP-Protokoll, soweit ich das beurteilen kann.

0

Auf mögliche Antwort ist, dass Sie ein "altes" Gerät haben können. Anscheinend Multicast (von Java) vor Android gebrochen 2.3.7

Referenz: https://stackoverflow.com/a/9836464/139985

Eine weitere Möglichkeit besteht darin, dass es sich um ein gerätespezifische Problem ist; z.B. so: https://stackoverflow.com/a/3714848/139985. (Ich sage nicht, es ist, dass spezifisches Problem ...)

Ein weiterer Grund ist, dass Multicast in den Kernel-Konfigurationen deaktiviert ist: http://code.google.com/p/android/issues/detail?id=51195

Es scheint, wie es eine Reihe von verschiedenen Ursachen für Multicast nicht arbeiten verschiedene Android-Geräte ...

+0

Ich führe dies auf Galaxy S3, Ice Cream Sandwich – l46kok

+0

Multicast funktioniert definitiv auf diesem Gerät, wie ich in der Lage, eine App vom Marktplatz zu bekommen, veröffentlichen Sie eine M-Search-Nachricht mit einer richtigen Antwort. Ich werde OP mit dem erfassten Paket bearbeiten. – l46kok

+0

Ich habe dann keine Ideen mehr. –

0

Ich folgte Ihrem Code und ändere einige Wörter in Großbuchstaben. Es klappt.

static final String HOST = "HOST: " + SSDPConstants.ADDRESS + ":" + SSDPConstants.PORT; 
static final String MAN = "MAN: \"ssdp:discover\""; 

Sie müssen die Reihenfolge in MSEARCH-Nachricht nicht ändern.