由於公司業務需求,近期要實現一個在同一局域網控制其他設備的功能。(就是手機端控制板子段驍龍410c的開發板)
其實設備只要能相互通信,就能很好的實現這種功能。可是在同一局域網,如何連接其他智能設備呢?-其實用過socket的朋友都知道,通過socket就能把兩個設備連接起來,並實現實時的通信。因爲socket 連接必須知道對方的IP,如果IP都不知道,兩個設備還是不能同行。
所以獲取設備IP就是我們首先要解決的問題。
(1)其實在局域網是可以允許設備發送廣播的,我們宿主設備可以往局域網內發送一段廣播。
(2)當被連接的設備收到我們的廣播時,被連接設備就可以回覆一個廣播給我們的宿主設備。
(3)利用scoket短鏈接控制server端燈泡的亮度
第一步向局域網內發送一個廣播:
//新開一個線程 client端
class SendMessage extends Thread {
@Override
public void run() {
// Send message;
while (!Thread.currentThread().isInterrupted()) {
String mes = "IP";
//把message轉成byte數組
byte[] buffer = mes.getBytes();
byte[] backbuff = new byte[2048];
//因爲下面的socket。recevice()會阻塞當前線程,無法不斷地往局域網發送廣播。所server端 未打開APP或者處於關機狀態建議把發送數據包的部分代碼獨立出來,不然server端接收不到廣播。
try {
Log.e("SEND", "ONE");
//利用java提供的DatagramSocket 進行操作,因爲其可以存放數據包。
socket = new DatagramSocket();
//把message加入datagramsocket裏。
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, boardcastIp, UdpPort);
//創建接受廣播的packet
DatagramPacket datagramPacket = new DatagramPacket(backbuff, backbuff.length);
//發送廣播
socket.send(packet);
//在接收廣播時,會阻塞當前的線程,一直等到超時,或接收到數據。
socket.receive(datagramPacket);
String res = new String(datagramPacket.getData(), 0, datagramPacket.getLength());
Log.e("SEND", "&&"+res);
if (res != null) {
//把接收到的地址保存起來!
saveIp.add(res);
Message message = handler.obtainMessage();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putString("res", res);
message.setData(bundle);
handler.sendMessage(message);
//如接收到結果,則把當前線程給結束。
SendMessage.this.interrupt();
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if (socket!=null){
//最後關閉Datagramsocket
socket.close();
}
}
}
}
}
服務端的實現:主要是接收 client 發出的packet,隨後發出一個packet(帶有自己的ip信息)
//開啓一個新線程,來接收局域網發來的消息:
public class acceptUDP extends Thread {
public DatagramSocket socket;
@Override
public void run() {
try {
//監聽本機的端口
socket = new DatagramSocket(UdpPort);
Log.i("WifiController", "***");
//創建一個buffer來接受client傳過來的數據
byte[] buffer = new byte[2048];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
Log.i("WifiController", "***");
while (true) {
//阻塞當前線程來接受數據
Log.i("WifiController", "%***%");
//接收局域網內的所有廣播
socket.receive(packet);
String re = new String(packet.getData(), 0, packet.getLength());
Log.i("WifiController", "&***&" + re);
//對廣播內容進行篩選
if (re.equalsIgnoreCase("IP")) {
String back = Build.MODEL + "&" + address;
Log.i("WifiController", back);
// 把當前機子的IP通過廣播發送到局域網中
DatagramPacket datagramPacket = new DatagramPacket(back.getBytes(), back.length(), packet.getSocketAddress());
socket.send(datagramPacket);
Log.i("WifiController", "" + packet.getSocketAddress());
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (socket != null) {
//最後關閉socket
socket.isClosed();
}
}
}
}
獲取IP地址的操作就到此結束了;
控制階段主要是通過socket通信來實現:
client:
public class Controll implements Runnable {
private String whitch;
private String code;
public Controll(String whitch, String code) {
this.whitch = whitch;
this.code = code;
}
@Override
public void run() {
String ip = MainActivity.store.get(whitch);
if (ip != null) {
try {
socket = new Socket(ip, PORT);
socket.setSoTimeout(2000);
PrintWriter printWriter = null;
try {
printWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())), true);
} catch (IOException e) {
e.printStackTrace();
}
printWriter.println(code);
Log.i("IP", socket.isConnected() + "");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
主要是創建多個socket短連接,併發送相應CODE,使服務端接收到相應的CODE之後做出相應Action:
Server:
//開啓一個線程監聽端口
class RecevieSocket extends Thread {
@Override
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
} catch (IOException e) {
e.printStackTrace();
}
Communication communication = new Communication(socket);
communication.start();
}
}
}
//開啓一個線程接受相應的數據
class Communication extends Thread {
private Socket socket;
private BufferedReader input;
private String code = null;
public Communication(Socket socket) {
this.socket = socket;
try {
this.input = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
Log.i("finderror", socket.isConnected() + "");
try {
code = input.readLine();
} catch (IOException e) {
e.printStackTrace();
}
//相應的控制燈光操作:
if (StringUtil.get(0, code, "@") != null) {
switch (StringUtil.get(0, code, "@")) {
case "close":
Config.WriteData(Config.color, "0");
break;
case "open":
Config.WriteData(Config.color, "10");
break;
case "red":
Config.WriteData(Config.color, "1");
break;
case "red_light":
Config.WriteData(Config.color, "4");
break;
case "green":
Config.WriteData(Config.color, "3");
break;
case "green_light":
Config.WriteData(Config.color, "6");
break;
case "blue":
Config.WriteData(Config.color, "2");
break;
case "blue_light":
Config.WriteData(Config.color, "5");
break;
case "white":
Config.WriteData(Config.color, "10");
break;
case "reserve_open":
Calendar calendar = Calendar.getInstance();
long sys= System.currentTimeMillis();
calendar.setTimeInMillis(sys);
calendar.set(Calendar.HOUR_OF_DAY,Integer.parseInt(StringUtil.get(3,code,"@")));
Log.i("close",StringUtil.get(3,code,"@"));
calendar.set(Calendar.MINUTE,Integer.parseInt(StringUtil.get(4,code,"@")));
Log.i("close",StringUtil.get(4,code,"@"));
Timer opentime =new Timer();
Log.i("close",(calendar.getTimeInMillis()-sys)+"");
opentime.schedule(new TimerTask() {
@Override
public void run() {
Log.i("result",StringUtil.get(1,code,"@")+"********"+StringUtil.get(2,code,"@")+"@@@@@@"+code);
Config.WriteData(Config.color,StringUtil.get(1,code,"@"));
Config.WriteData(Config.brightness,StringUtil.get(2,code,"@"));
}
},calendar.getTimeInMillis()-sys,(1000 * 60 * 60 * 24));
break;
case "reserve_close":
Calendar ca = Calendar.getInstance();
long system= System.currentTimeMillis();
ca.setTimeInMillis(system);
ca.set(Calendar.HOUR_OF_DAY,Integer.parseInt(StringUtil.get(1,code,"@")));
ca.set(Calendar.MINUTE,Integer.parseInt(StringUtil.get(2,code,"@")));
Timer close =new Timer();
close.schedule(new TimerTask() {
@Override
public void run() {
Config.WriteData(Config.color, "0");
}
},ca.getTimeInMillis()-system, (1000 * 60 * 60 * 24));
break;
case "brightness":
Config.WriteData(Config.brightness, Integer.parseInt(StringUtil.get(1, code, "@")) * 10 + "");
break;
}
}
}
}
}
Config.WriteData(Config.color, “0”);這句代碼是對驍龍410c的開發板上的燈光進行控制。(往節點裏些不同的數據!)