无法使用SSDP接收正确的UDP数据包



我正试图实现一个非常简单的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 = "rn";
    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

毫无疑问,这是一个实现问题。设备没有问题

奇怪。我修复了这个问题,但我真的不确定是什么使它工作。

我做了一些修改:

我让它动态地分配一个可用的端口,而不是分配一个固定的端口。

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 = "rn";
    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协议。

一个可能的答案是你可能有一个"旧"的设备。显然多播(来自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设备上工作…

我按照你的代码把一些单词改成了大写。它的工作原理。

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

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

相关内容

  • 没有找到相关文章

最新更新