由于公司业务需求,近期要实现一个在同一局域网控制其他设备的功能。(就是手机端控制板子段骁龙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的开发板上的灯光进行控制。(往节点里些不同的数据!)