大家好,又见面了,我是全栈君,祝每个程序员都可以多学几门语言。
前面一篇博客里面已经介绍过SSDP协议原理,本篇博客将实现实现Android上的SSDP协议。
关键技术分析:1、发送广播;须要发送送广播,所以须要使用MulticastSocket、SocketAddress、InetAddress,须要掌握。
2、SSDP数据报格式;标准的SSDP Server解析的时候对于分段的字段选用的特征码是”rn”,须要特别注意。
3、訪问权限;须要互联网,要在Mainfest中加入�联网的相关权限。
下面是我的源代码:
1、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; 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 = “rn”; 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 = “rn”; 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.cn/118542.html原文链接:https://javaforall.cn