前面一篇博客里面已经介绍过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



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

更多相关文章

  1. Android设备和PC端通过USB线通信
  2. Android(安卓)sqlite 采用execSQL和rawQuery方法完成数据的添删
  3. android适配器SimpleCursorAdapter的使用以及最后一个参数的作用
  4. Android(安卓)渗透测试学习手册 第六章 玩转 SQLite
  5. 详解Android轻量型数据库SQLite
  6. android sql
  7. 获取web服务器xml数据
  8. Android(安卓)Data Binding 技术
  9. 关于Android中传递数据的一些讨论

随机推荐

  1. 【点宽专栏】——ORB突破
  2. 【RS】导出路由器/交换机配置的方法
  3. 自然语言处理集训营第一期
  4. 【点宽专栏】天风证券——商品期货CTA专
  5. 有人梦到国自然,我居然梦到看文献!
  6. 给大家分享一个一键采集哔哩哔哩短视频素
  7. Cell杂志背靠背的两篇文章:看不同研究团队
  8. 【点宽专栏】基于贝叶斯统计的套利策略(上
  9. 全国首个!广州推出22条举措打造世界级钻石
  10. 【点宽专栏】——Pivot Point交易法