7

我正在尝试将一个非常简单的 SSDP 功能实现到从这里获取的我的 android 应用程序中。

我的应用程序将一些包含相关 M-SEARCH 消息的 UDP 数据包发送到广播地址,没有任何问题。问题是,我应该从运行 UPNP 服务器的其他设备得到正确的响应。出于某种原因,我只收到了从我的 android 设备发送回来的完全相同的数据包。

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 实际完成 UDP 数据包传输的地方

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 用于构建 SSDP 广播字符串(可能与我遇到的问题无关,但以防万一)

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";
}

我还确保清单包含相关权限:

 <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" />

我正在实际设备上测试应用程序,而不是在模拟器上。

任何援助将不胜感激。

根据评论编辑:

多播本身应该可以正常工作。我下载了一个名为 BubbleUPNP 的应用程序来测试 SSDP 功能。果然,wireshark 正确地捕获了所有从手机发送到 SSDP 协议中的广播地址的消息:

M-SEARCH * HTTP/1.1

Man: "ssdp:discover"

Mx: 3

Host: 239.255.255.250:1900

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

和回应

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

所以,是的,毫无疑问,这是一个实施问题。设备没有问题。

4

3 回答 3

4

奇怪的。我解决了这个问题,但我真的不确定是什么使它起作用。

以下是我所做的一些更改:

我没有分配固定端口,而是让它动态分配一个可用端口。

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

    public SSDPSocket() throws IOException {

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

我还更改了 M-Search 消息结构,包括其顺序。

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();
    }
}

一切都突然起作用了。为什么它起作用超出了我的范围。据我所知,我之前的实现遵循 SSDP 协议。

于 2013-06-09T05:53:36.803 回答
0

可能的答案是您可能有一个“旧”设备。显然多播(来自 Java)在 Android 2.3.7 之前被破坏

参考:https ://stackoverflow.com/a/9836464/139985

另一种可能性是它是特定于设备的问题。例如像这样:https ://stackoverflow.com/a/3714848/139985 。(我不是说这是那个特定的问题......)

另一个是内核配置中禁用了多播:http://code.google.com/p/android/issues/detail?id=51195

似乎有一系列不同的原因导致多播无法在各种 Android 设备上运行......

于 2013-04-01T14:00:07.463 回答
0

我按照您的代码将一些单词更改为大写。有用。

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

不需要更改 MSEARCH 消息中的顺序。

于 2014-04-10T04:21:25.923 回答