SSDP协议的Android实现以及使用

SSDP协议的Android实现以及使用

大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。

前面一篇博客里面已经介绍过SSDP协议原理,本篇博客将实现实现Android上的SSDP协议。

关键技术分析:1、发送广播;须要发送送广播,所以须要使用MulticastSocket、SocketAddress、InetAddress,须要掌握。

    2、SSDP数据报格式;标准的SSDP Server解析的时候对于分段的字段选用的特征码是”\r\n”,须要特别注意。

    3、訪问权限;须要互联网,要在Mainfest中加入�联网的相关权限。

下面是我的源代码:

1、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;
public static final String SL_MSEARCH = “M-SEARCH * HTTP/1.1”;
public static final String SL_OK = “HTTP/1.1 200 OK”;
public static final String ST_Product = “ST:urn:schemas-upnp-org:device:Server:1”;
public static final String Found = “ST=urn:schemas-upnp-org:device:”;
public static final String Root = “ST:urn:schemas-upnp-org:device:DZBA_HomeDP:1”;
}

2、SSDPSearchMsg .java

public class SSDPSearchMsg {
static final String HOST = “Host:” + SSDP.ADDRESS + “:” + SSDP.PORT;
static final String MAN = “Man:\”ssdp:discover\””;
static final String NEWLINE = “\r\n”;
int mMX = 5; /* 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(“MX:” + mMX).append(NEWLINE);
content.append(mST).append(NEWLINE);
content.append(NEWLINE);
return content.toString();
}
}

3、SSDPSocket .java

public class SSDPSocket {

SocketAddress mSSDPMulticastGroup;
MulticastSocket mSSDPSocket;
InetAddress broadcastAddress;

public SSDPSocket() throws IOException {
mSSDPSocket = new MulticastSocket(58000); // 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();
}
}
}

4、SSDP .java

public class SSDP {
/* 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;
public static final String ST = “ST”;
public static final String LOCATION = “LOCATION”;
public static final String NT = “NT”;
public static final String NTS = “NTS”;
/* 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”;

@SuppressWarnings(“resource”)
public static String parseHeaderValue(String content, String headerName) {
Scanner s = new Scanner(content);
s.nextLine(); // Skip the start line
while (s.hasNextLine()) {
String line = s.nextLine();
int index = line.indexOf(‘:’);
String header = line.substring(0, index);
if (headerName.equalsIgnoreCase(header.trim())) {
return line.substring(index + 1).trim();
}
}
return null;
}

public static String parseHeaderValue(DatagramPacket dp, String headerName) {
return parseHeaderValue(new String(dp.getData()), headerName);
}

@SuppressWarnings(“resource”)
public static String parseStartLine(String content) {
Scanner s = new Scanner(content);
return s.nextLine();
}

public static String parseStartLine(DatagramPacket dp) {
return parseStartLine(new String(dp.getData()));
}
}

5、MainActivity .java

public class MainActivity extends Activity implements OnClickListener {
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.Root);
SSDPSocket sock = null;
try {
sock = new SSDPSocket();
for (int i = 0; i < 2; i++) {
// sock.send(searchContentDirectory.toString());
// sock.send(searchAVTransport.toString());
sock.send(searchProduct.toString());
// String s = “M-SEARCH * HTTP/1.1 \n HOST= 239.255.255.250:1900 \n MAN= \”ssdp:discover\” \n MX: 3 \n ST= upnp:rootdevice”;
// sock.send(s);
Log.i(“————-“, “发送的数据为:\n” + 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()).trim();
String ip = new String(dp.getAddress().toString()).trim();
Log.i(“————“, “接收到的数据为:\n” + c + “數據來源IP:” + ip);
}
} catch (IOException e) {
Log.e(“M-SEARCH”, e.getMessage());
}
}
}

界面xml非常easy,仅仅有一个button

Mainfest.xml:

<?xml version=”1.0″ encoding=”utf-8″?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android”
    package=”com.example.ssdp”
    android:versionCode=”1″
    android:versionName=”1.0″ >

    <uses-sdk
        android:minSdkVersion=”8″
        android:targetSdkVersion=”18″ />

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

    <application
        android:allowBackup=”true”
        android:icon=”@drawable/ic_launcher”
        android:label=”@string/app_name”
        android:theme=”@style/AppTheme” >
        <activity
            android:name=”com.example.ssdp.MainActivity”
            android:label=”@string/app_name” >
            <intent-filter>
                <action android:name=”android.intent.action.MAIN” />

                <category android:name=”android.intent.category.LAUNCHER” />
            </intent-filter>
        </activity>
    </application>

</manifest>

使用须知:须要有Server端执行,http://download.csdn.net/detail/zhu530548851/7451201下载源代码,该源代码是js的。

将Server放于Linux系统文件夹下,进入test文件夹,运行node server.js就可以。

须要Linux安装有nodejs:sudo apt-get install nodejs

这样在执行Androidclient就能够从Log中看到来自于Server的信息了。

Android源代码在此:http://download.csdn.net/detail/zhu530548851/7451179

个人辛勤劳动成果,如有转载,请注明出处,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/118542.html原文链接:https://javaforall.net

(0)
上一篇 2021年12月4日 下午7:00
下一篇 2021年12月4日 下午8:00


相关推荐

  • Spring Boot Starters介绍[通俗易懂]

    Spring Boot Starters介绍[通俗易懂]文章目录WebStartTestStarterDataJPAStarterMailStarter结论对于任何一个复杂项目来说,依赖关系都是一个非常需要注意和消息的方面,虽然重要,但是我们也不需要花太多的时间在上面,因为依赖毕竟只是框架,我们重点需要关注的还是程序业务本身。这就是为什么会有SpringBootstarters的原因。StarterPOMs是一系列可以被引用的依赖…

    2025年7月13日
    4
  • GenAI Agents邮件处理:记忆增强邮件智能体的自动回复技术

    GenAI Agents邮件处理:记忆增强邮件智能体的自动回复技术

    2026年3月15日
    2
  • SVN服务器部署「建议收藏」

    SVN服务器部署「建议收藏」1,关闭防火墙或者开放对应端口3690,2,Yum下载安装subversion检查SVN是否安装成功svnserve–version3,建立SVN版本库3.1因为大磁盘挂载在/home下,所以我是在/home下创建的版本库,mkdir/home/svn创建一个文件夹(所有项目库都在此目录下创建)3.2创建svn版本库svnadmincreate/home/svn/liangz_artliangz_art才是项目版本库的名字,后面开发人员checkout时就要用这个名称,项

    2022年7月19日
    21
  • 一文详解python中的数据库操作

    一文详解python中的数据库操作python 中的数据库操作一 数据库编程接口 1 连接对象二 使用内置的 SQLite1 创建数据库文件 2 操作 SQLite 三 MySql 数据库的使用 3 1 安装 MySql3 2 设置环境变量 3 3 启动 MySql3 4 使用 navicatformy 管理软件 3 5 安装 PyMysql 模块 3 6 连接数据库四 创建数据表 4 1 创建 books 图书表 4 2 操作 MySql 数据表最近做毕设 需要添加个数据库 记录一下 一 数据库编程接口重点介绍数据库 API 接口中的连接对象和游标对象 1 连接对

    2026年3月17日
    1
  • foremost入门

    foremost入门foremostvers 5 7byJesseKorn KrisKendall andNickMikus foremost v V h T Q q a w d t type s blocks k size b size c size size blocks type

    2026年3月18日
    3
  • ETAP软件–可靠性计算

    ETAP软件–可靠性计算对单辐射架空线路进行可靠性计算过程。图1单辐射架空线路分段接线图各元件可靠性参数如下:架空线路故障停运率(次/百公里) 55.865架空线路停电平均持续时间(小时) 4.1622断路器故障停运率(次/百台) 1.699断路器停电平均持续时间(小时) 4.8864开关故障停运率(次/百台) 54.677开关停电平均持续时间(小时) 1.9361每个负荷点带2个用户,架空线路长度,…

    2022年7月14日
    27

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号