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