【Android开发—智能家居系列】(四):UDP通信发送指令

来源:互联网 发布:三级网络技术模拟软件 编辑:程序博客网 时间:2024/05/11 22:48

思路回顾

【1】手机连接WIFI模块
【2】UDP通信对WIFI模块发送指令,以和WIFI模块保持连接状态
【3】UDP通信对WIFI模块发送指令,让其搜索可用的无线网,返回WIFI列表
【4】发送指令,让WIFI模块接入指定路由
【5】手机连接路由
【6】发送指令,获得WIFI模块的动态IP地址

UDP通信线程类

package com.jczb.smartlife.common;import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;import java.net.InetSocketAddress;import java.net.SocketException;import java.net.UnknownHostException;import android.os.Handler;import android.os.Message;import com.jczb.smartlife.common.Tool;public class GetInfoThread extends Thread {    private Handler handler;    private DatagramSocket socket;    private int msgType;    private final String IP = "255.255.255.255";//广播地址    private int PORT = 26000;    /**     * 48899端口:C32x系列的端口,用户可以用AT指令更改     * 49000端口:除C32x系列,其他WIFI模块的端口     * 1902端口:有人掌控宝系列产品的端口     */    private int targetPort = 49000 ;    private boolean receive = true;    /**     *      * @param handler 传入监听此线程的Handler     * @param intMsg 传入监听的消息类型     */    public GetInfoThread(Handler handler,int msgType) {        this.handler = handler;        this.msgType=msgType;        init();    }    public void init(){        try {            socket = new DatagramSocket(null);            socket.setBroadcast(true);            socket.setReuseAddress(true);            socket.bind(new InetSocketAddress(PORT));        } catch (SocketException e) {            e.printStackTrace();            sendErrorMsg("Search Thread init fail");            return;        }     }    public void run() {        if (socket == null) {            return;        }        try {            byte[] data = new byte[1024];            //创建一个空的DatagramPacket对象            DatagramPacket revPacket = new DatagramPacket(data, data.length);            while (receive) {                //服务端接收数据                socket.receive(revPacket);                if(null!=handler){                    byte[] realData = new byte[revPacket.getLength()];                    System.arraycopy(data, 0, realData,0, realData.length);                    Message msg =handler.obtainMessage(msgType,realData);                    handler.sendMessage(msg);                }            }        } catch (Exception e) {            e.printStackTrace();            socket.close();        }    }    public void close() {        if (socket == null)            return;        socket.close();    }    private void sendErrorMsg(String info){    }    /**     * 发送数据     * @param msg     */    public void sendMsg(byte[] msg) {        if (socket != null) {            try {                System.out.println("targetPort------------------->"+targetPort);                DatagramPacket sendPacket = new DatagramPacket(msg, msg.length,                        InetAddress.getByName(IP), targetPort);                socket.send(sendPacket);            } catch (UnknownHostException e) {                e.printStackTrace();                System.out.println("发送失败");            } catch (IOException e) {                e.printStackTrace();                System.out.println("发送失败");            }        }    }    public void setReceive(boolean receive) {        this.receive = receive;    }    public void setTargetPort(int targetPort) {        this.targetPort = targetPort;    }    public void setMsgType(int msgType){        this.msgType=msgType;    }}

发送消息的线程类

/**     * 发送消息的队列,每次发送数据时,只需要调用putMsg(byte[] data)方法     *      * @author usr_liujinqi     *      */    private class SendMsgThread extends Thread {        // 发送消息的队列        private Queue<byte[]> sendMsgQuene = new LinkedList<byte[]>();        // 是否发送消息        private boolean send = true;        private GetInfoThread ss;        public SendMsgThread(GetInfoThread ss) {            this.ss = ss;        }        public synchronized void putMsg(byte[] msg) {            // 唤醒线程            if (sendMsgQuene.size() == 0)                notify();            sendMsgQuene.offer(msg);        }        public void run() {            synchronized (this) {                while (send) {                    // 当队列里的消息发送完毕后,线程等待                    while (sendMsgQuene.size() > 0) {                        byte[] msg = sendMsgQuene.poll();                        if (ss != null)                            ss.sendMsg(msg);                    }                    try {                        wait();                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }        public void setSend(boolean send) {            this.send = send;        }    }

应用

【举例】发送搜索WIFI模块的指令

//1.用户获得温控器中WIFI模块的WIFI模块的IP地址,MAC地址,模块名称的指令        private final byte[] getInfoCode=new byte[]{(byte)0x48,0x46,0x2D,0x41,0x31,0x31,0x41,0x53,0x53,0x49,0x53,0x54,0x48,0x52,0x45,0x41,0x44};    public static final int REC_Module=0x04;//搜索WIFI模块的信息(包括IP、Mac、名称)//实例化一个线程,用户获得模块信息(IP,Mac,名称)        //参数为监听为此线程的Handler,以及接收成功后,给Handler发送的消息类型        getInfoThread = new GetInfoThread(handler,Tool.REC_Module);        getInfoThread.start();        //发送消息的线程        smt = new SendMsgThread(getInfoThread);        smt.start();        //设置发送的目的端口号        getInfoThread.setTargetPort(Integer.parseInt("48899"));             smt.putMsg(getInfoCode);

WIFI模块在接收到指令后,就会回复信息,以下的Handler就是针对回复过来的信息进行解析处理等操作。

//处理消息的Handler    private Handler handler= new Handler() {        public void handleMessage(Message msg) {            switch (msg.what) {            case Tool.REC_Module:// 解析接收到的数据                //设置发送的目的端口号                getInfoThread.setTargetPort(Integer.parseInt("48899"));                 getInfoThread.setMsgType(Tool.REC_OK);                smt.putMsg(okCode);                SetServer();                SetDHCP();                byte[] data = (byte[]) msg.obj;                //将十进制的数据转化成十六进制数据                String strTemp= Tool.bytesToHexString(data);                //将十六进制的字符串去掉空格之后进行解析                String strdecode=Tool.DecodeHex(strTemp.replace(" ", ""));                //取出IP,Mac地址,模块名称                decodeIP(strdecode);                Toast.makeText(ConnectWifiActivity.this, "获得WIFI模块名称成功!"+ModuleName, Toast.LENGTH_SHORT).show();                break;            case Tool.REC_Server:                byte[] dataServer = (byte[])msg.obj;                //将十进制的数据转化成十六进制数据                String strServer= Tool.bytesToHexString(dataServer);                if("2b 6f 6b 0d 0a 0d 0a ".equals(strServer)){                    Toast.makeText(ConnectWifiActivity.this, "设置服务器成功!", Toast.LENGTH_SHORT).show();                }                break;            case Tool.REC_SSID:                byte[] dataSSID=(byte[])msg.obj;                Tool.bytesToHexString(dataSSID);                decodeData(dataSSID);                break;            case Tool.REC_AT:                byte[] dataID = (byte[]) msg.obj;                //将十进制的数据转化成十六进制数据                String strTempID= Tool.bytesToHexString(dataID);                //将十六进制的字符串去掉空格之后进行解析                String strdecodeID=Tool.DecodeHex(strTempID.replace(" ", ""));                break;            case Tool.REC_DHCP:                byte[] dataDHCP = (byte[])msg.obj;                //将十进制的数据转化成十六进制数据                String strDHCP= Tool.bytesToHexString(dataDHCP);                if("2b 6f 6b 0d 0a 0d 0a ".equals(strDHCP)){                    Toast.makeText(ConnectWifiActivity.this, "设置DHCP网络参数成功!", Toast.LENGTH_SHORT).show();                }                break;            default:                byte[] data1 = (byte[]) msg.obj;                //将十进制的数据转化成十六进制数据                String strTemp1= Tool.bytesToHexString(data1);                Toast.makeText(ConnectWifiActivity.this, strTemp1, Toast.LENGTH_SHORT).show();                break;            }        }    };

总结

  凡是需要对WIFI模块发送指令的,就需要用到上述的两个线程类,还有一个对返回信息进行处理的Handler。只是发送的指令的code不一样,如上述表示的是搜索WIFI模块的十六进制的指令。不管WIFI模块在AP模式下还是STA模式,通信的最开始步骤都是先搜索模块,然后获得它的IP和Mac之后,立即回复+ok指令,就可以保持连接状态。

Demo下载

UDP通信发送指令Demo

4 0
原创粉丝点击