最近做了一个TCP连接android与单片机的项目。记录一下。

TCP连接对象

首先是TCP连接,以前没有做过,摘抄的同事项目中TCP连接对象。
public class TCPChannel {
    private SocketChannel myChannel = null;
    private boolean isConnecting = true;
    private boolean isConnected = false;
    // 发送心跳包的线程是否已经关闭
    private boolean isSendHeartBreak = false;
    private Selector selector = null;
    private Iterator iterator;
    private SelectionKey key;
    private String mac = "";
    private SocketAddress address;
    private int timeOut;
    private Thread heartbeat;

    private int heartCunt = 0;
    private boolean isWaitHeart = false;

    public TCPChannel(SocketChannel socketChannel, SocketAddress address,
            int timeOut) {
        // TODO Auto-generated constructor stub
        myChannel = socketChannel;
        this.address = address;
        this.timeOut = timeOut;
        try {
            LogUtil.e("selector open is will run open!!");
            selector = Selector.open();
        } catch (IOException e) {
            LogUtil.e("Selector.open() is wrong XXXX");
            e.printStackTrace();
        }
    }

    public void connect() throws IOException, NullPointerException {
        LogUtil.e("connect is be runned!!");

        isConnecting = true;
        isConnected = false;
        System.out.println(myChannel.toString());
        myChannel.configureBlocking(false);
        if (selector == null)
            throw new NullPointerException(mac);
        myChannel.register(selector, SelectionKey.OP_CONNECT
                | SelectionKey.OP_READ | SelectionKey.OP_WRITE);
        myChannel.connect(address);

        // System.out.println("检查TCP连接:" + checkConnect());
        if (checkConnect()) {
            LogUtil.e("checkConnect return true");
        } else {
            this.close();
            LogUtil.e("checkConnect return false");

        }
    }

    public void reConnect() {
        Log.w("重练空调", "准备开始");
        if (!isConnected) {
            return;
        }
        isConnecting = true;
        isConnected = false;
        if (heartbeat != null) {
            heartbeat.interrupt();
        } else {
            System.out.println("重连接时候心跳为空");
            // sendHeartbeat();
        }
        try {
            Log.w("重练空调", "关闭连接");
            myChannel.socket().close();
            myChannel.close();
            selector.close();
            myChannel = SocketChannel.open();
            try {
                selector = Selector.open();
            } catch (IOException e) {
                Log.e("----->", "Selector.open()错误2");
                e.printStackTrace();
            }
            Log.w("重练空调", "正在重连");
            try {
                connect();
            } catch (NullPointerException e) {
                isConnected = true;
                Log.e("----->", e + "抛出空指针异常33");
            }

            if (!isConnected) {
                Log.w("重练空调", "没有连上");

                close();
            } else {
                Log.w("重练空调", "重连成功");
                Log.i("----->12.4", "重连成功?" + heartCunt + " "
                        + isSendHeartBreak);

                // 在断开wifi的情况下,心跳线程异常会从而终止,此判断是如果心跳因为异常而终止则重新开启心跳
                if (heartCunt < 3) {
                    if (isSendHeartBreak) {
                        // sendHeartbeat();
                    }
                } else {
                    close();
                }
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ConcurrentModificationException e) {
            e.printStackTrace();
            close();
        }
    }

    public boolean checkConnect() {
        isConnected = false;
        try {
            Thread.sleep(timeOut * 1000);

        } catch (InterruptedException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try {
            LogUtil.e("check TCP connection is:::-->" + myChannel
                    + "                   " + myChannel.finishConnect()
                    + "            " + myChannel.isConnected());
            if (myChannel != null && myChannel.finishConnect()
                    && myChannel.isConnected()) {

                LogUtil.e(" not null 重连的时候?");
                isConnected = true;
            }
        } catch (Exception e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        isConnecting = false;
        return isConnected;
    }

    public void send(byte[] bytes) {
        // TODO Auto-generated method stub
        if (!isConnected || isConnecting) {
            return;
        }
        System.out.println("bytes  " + bytes + "myChannel  " + myChannel);
        try {
            ByteBuffer buf = ByteBuffer.wrap(bytes);
            myChannel.write(buf);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public int sendUpdateDate(byte[] bytes) {
        // TODO Auto-generated method stub
        if (!isConnected || isConnecting) {
            return -1;
        }
        System.out.println("bytes  " + bytes + "myChannel  " + myChannel);
        try {
            ByteBuffer buf = ByteBuffer.wrap(bytes);
            myChannel.write(buf);
            return 0;
        } catch (IOException e) {

            e.printStackTrace();
            return -2;
        }
    }

    public void receive(Handler mainHandler) throws ParseException {

        // LogUtil.e("in receive ...");
        if (!isConnected || isConnecting) {
            return;
        }
        // LogUtil.e("in receive 校验之后 ");
        try {
            selector.select(100);
            if (selector != null && selector.isOpen()) {
                // LogUtil.e("selector校验  selector != null && selector.isOpen()");
                iterator = selector.selectedKeys().iterator();
            } else {
                return;
            }
            while (iterator.hasNext()) {
                // LogUtil.e("进入while循环内, iterator.hasNext()");
                key = iterator.next();
                // LogUtil.e("key == "+key.toString());
                // 删除正在处理的SelectionKey
                iterator.remove();
                // 如果该SelectionKey对应的Channel中有可读的数据
                // 测试此键的通道是否已准备好接受新的套接字连接。
                ServerSocketChannel server = null;
                SocketChannel client = null;
                if (key.isReadable()) {
                    LogUtil.e("key.isReadable() 为true了  有可读数据");
                    // 使用NIO读取Channel中的数据
                    SocketChannel sc = (SocketChannel) key.channel();
                    // ByteArrayOutputStream buff = new
                    // ByteArrayOutputStream(1024 );//缓冲
                    // ByteArrayOutputStream有toByteArray()方法 直接得到数据
                    ByteBuffer buff = ByteBuffer.allocate(256);
                    String content = "";
                    int i = 0;
                    // //161 23.97
                    while ((i = sc.read(buff)) > 0) {
                        sc.read(buff);
                        buff.flip();
                        byte[] bytes = new byte[i];
                        buff.get(bytes);
                        switch (i) {
                        case 97:// 1-46
                            BatteryInfo batteryInfo = SaveUtil
                                    .saveBatteryInfo(bytes);
                            if(batteryInfo!=null){
                                Message msg = new Message();
                                Bundle b = new Bundle();// 存放数据
                                b.putSerializable("BatteryInfo",
                                        (Serializable) batteryInfo);
                                msg.setData(b);
                                msg.what= 2;
                                LogUtil.e("发送数据97的、、、");
                                mainHandler.sendMessage(msg);
                            }
                            // 1.bytes,先截取前三个,后二个。留中间数据.返回三个数组
                            // 2。数据分开保存至bean中
                            // 2.1前三个直接把无符号byte转为int存储。
                            // 2.2中间数组两个合并一个,合并后,获取到short的无符号int值存储bean
                            // 2.2.1 数据格38-43四个合成一个转成long存储bean中。
                            // 2.3后两个变成16进制存储到CRC高低字节中。
//                            LogUtil.e(batteryInfo.toString());
                            break;
                        case 161:// 80-158

                            break;
                        case 25:// 60-69
                            BatteryWarmInfo saveBatteryWarmInfo = SaveUtil
                                    .saveBatteryWarmInfo(bytes);
//                            LogUtil.e(saveBatteryWarmInfo.toString());
                            // 判断saveBatteryWarmInfo.警告信息集合长度,如果有数据,更新界面
                            if (saveBatteryWarmInfo.WarmInfos.size() > 0) {
                                // TODO发送消息到 MainUIThread 线程更新界面??
                                // mainHandler.
                                Message msg = new Message();
                                Bundle b = new Bundle();// 存放数据
                                b.putSerializable("warmInfos",
                                        (Serializable) saveBatteryWarmInfo);
                                msg.setData(b);
                                msg.what= 1;
                                LogUtil.e("发送数据 25的、、、");
                                mainHandler.sendMessage(msg);
                                
                            }
                            break;

                        default:
                            LogUtil.e("获取到未知长度数据!请复查代码");
                            break;
                        }

                        // for (int x = 0; x < i; x++) {
                        // LogUtil.e(Byte.toString(bytes[x]));
                        // }
                        buff.clear();
                    }

                    key.interestOps(SelectionKey.OP_READ);
                    if (i == -1) {
                        reConnect();
                    }
                }

            }
            // LogUtil.e("跳出while循环, iterator.hasNext()");
        } catch (IOException e1) {
            e1.printStackTrace();
        }

    }

    public void close() {
        isConnecting = true;
        isConnected = false;
        selector = null;
        mac = null;
        try {
            myChannel.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (NullPointerException e) {
            Log.w("TCP关闭", "空指针");
        }
        myChannel = null;
    }

    public String getMac() {
        return mac;
    }

    public boolean isConnected() {
        return isConnected;
    }

    // private void ProcessReply(String id, List strs) {
    // JsonParser parser = new JsonParser();
    // for (String str : strs) {
    //
    // System.out.println("str====:" + str);
    // // 改用正则匹配
    // if (str.matches("\\{.*\\}")) {
    //
    // System.out.println("没有问题啊!!!!!!!!!!!!!!!!");
    //
    // JsonElement jsonEl = parser.parse(str);
    // JsonObject jsonObj = null;
    // jsonObj = jsonEl.getAsJsonObject();
    // JsonElement je;
    // if ((je = jsonObj.get("response_type")) != null
    // && je.getAsInt() == 2) {
    // heartCunt = 0;
    // isWaitHeart = false;
    // } else {
    // Control.receivedPackets(gApp, jsonObj, TCPChannel.this);
    // }
    // } else {
    // System.out.println(id + "回码有问题啊!!!!!!!!!!!!!!!!" + str);
    // GreeApplication.baseActivity.showToast(id + "局域网回码错误");
    // }
    // }
    // }

    // public void sendHeartbeat() {
    // isSendHeartBreak = false;
    // heartbeat = new Thread(mac + "心跳") {
    // public void run() {
    // while (isConnected && !isConnecting) {
    // try {
    // Log.i("心跳包",
    // "心跳包发送"
    // + mac
    // + "       "
    // + JsonUtil.toJsonString(new Heartbeat(
    // GreeTime.getTimestamp())));
    //
    // String heartPacket = JsonUtil
    // .toJsonString(new Heartbeat(GreeTime
    // .getTimestamp())); // 加密
    //
    // String key = GreeApplication.LANKeymap.get(mac);
    // if (key == null) {
    //
    // key = "fbaef480";
    // }
    //
    // try {
    // heartPacket = Des.encryptDES(heartPacket, key,
    // false);
    // } catch (Exception e1) {
    // // TODO Auto-generated catch block
    // e1.printStackTrace();
    // }
    //
    // System.out.println("=================心跳des加密:" + key);
    // send(HeadUtil.addHead(heartPacket));
    // isWaitHeart = true;
    // sleep(10 * 1000);
    // if (isWaitHeart && heartCunt++ > 1) {
    // // 网络断开操作
    // Log.i("心跳包", "心跳包检测到网络断开" + mac);
    // reConnect();
    // }
    // } catch (UnsupportedEncodingException e) {
    // Log.i("----->12.4", "1:heart  error " + e.toString());
    // isSendHeartBreak = true;
    // e.printStackTrace();
    // } catch (InterruptedException e) {
    // Log.i("----->12.4", "2:heart  error " + "num is "
    // + heartCunt + "   " + e.toString());
    // isSendHeartBreak = true;
    // e.printStackTrace();
    // }
    // }
    // }
    // };
    // // ScheduledThreadPoolExecutor scheduler = new
    // // ScheduledThreadPoolExecutor(1);
    // // scheduler.schedule(heartbeat, 1,TimeUnit.SECONDS);
    // heartbeat.start();
    // }

    // private void checkTiming() throws ParseException {
    // // TODO Auto-generated method stub
    // DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss",
    // Locale.getDefault());
    // Date _date = new Date();
    //
    // String time_str = df.format(_date);
    //
    // System.out.println("定时现在时间:" + time_str);
    // if (AirCtrlDB.mPowerOnTimer != null) {
    // if (AirCtrlDB.mPowerOnTimer.bTimerOn) {
    // // System.out.println("//ON ");
    // time_str = time_str.substring(0, 11)
    // + AirCtrlDB.mPowerOnTimer.mHours + ":"
    // + AirCtrlDB.mPowerOnTimer.mMin + ":00";
    // long timeInterval = GreeTime.getInstance().timeIntervalNow(
    // time_str);
    // //
    // Log.i("----->12.4","在定时开机的循环中:"+AirCtrlDB.mPowerOnTimer.mfireMode+"   "+Math.abs(timeInterval));
    // if (Math.abs(timeInterval) < 4000) {
    //
    // System.out.println("//on < 36 ");
    // boolean _Execution = true;
    // switch (AirCtrlDB.mPowerOnTimer.mfireMode) {
    // case Timer_Mode_Once:
    // AirCtrlDB.mPowerOnTimer.bTimerOn = false;
    // break;
    // case Timer_Mode_WorkDay:
    // if (ByteOrder.getDay(_date) < 6) {
    //
    // } else {
    // _Execution = false;
    // }
    // break;
    // }
    // if (_Execution) {
    // // 开机
    // Log.i("----->12.4", "开机");
    // System.out.println("//on //开机 ");
    // ByteOrder.setpoweronView();
    // }
    //
    // }
    //
    // }
    // }
    //
    // if (AirCtrlDB.mPowerOffTimer != null) {
    // if (AirCtrlDB.mPowerOffTimer.bTimerOn) {
    // // System.out.println("//Off ");
    // /*
    // * DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    // * Date _date = new Date(); String time_str = df.format(_date);
    // */
    // time_str = time_str.substring(0, 11)
    // + AirCtrlDB.mPowerOffTimer.mHours + ":"
    // + AirCtrlDB.mPowerOffTimer.mMin + ":00";
    // long timeInterval = GreeTime.getInstance().timeIntervalNow(
    // time_str);
    // //
    // Log.i("----->12.4","在定时关机的循环中:"+AirCtrlDB.mPowerOffTimer.mfireMode+"   "+Math.abs(timeInterval));
    // if (Math.abs(timeInterval) < 4000) {
    // System.out.println("//off < 36 ");
    // boolean _Execution = true;
    // switch (AirCtrlDB.mPowerOffTimer.mfireMode) {
    // case Timer_Mode_Once:
    // AirCtrlDB.mPowerOffTimer.bTimerOn = false;
    // break;
    // case Timer_Mode_WorkDay:
    // if (ByteOrder.getDay(_date) < 6) {
    //
    // } else {
    // _Execution = false;
    // }
    // break;
    // }
    //
    // if (_Execution) {
    // // 关机
    // System.out.println("//off //关机 ");
    // ByteOrder.setpowerOffView();
    // }
    // }
    // }
    // }
    //
    // }

}
此类的几个主要方法简单说明下:

1.TCPChannel(SocketChannel socketChannel, SocketAddress address,int timeOut)

初始化对象,SocketChannel,SocketAddress  java api对象。

2.connect()

连接方法.内部调用了SocketChannel的register(selector, SelectionKey.OP_CONNECT| SelectionKey.OP_READ | SelectionKey.OP_WRITE);和connect(address);

3.reConnect()

重连socket,

4.send(byte[] bytes)

发送byte数组数据。

5.receiver();

数据接收。

调用方式:

先执行,接收数据的循环,接收到数据,就发送给主线程的handler

jieshou = new jieshou("TCP循环检测接收");
        jieshou.start();


private class jieshou extends Thread {
        public jieshou(String string) {
            this.setName(string);
        }

        @Override
        public void run() {
            super.run();
            LogUtil.e("接收线程run方法中 ");

            while (true) {
                try {
                    if (tcpChannel != null) {

                        tcpChannel.receive(mainHandler);

                    }
                    sleep(100);
                } catch (Exception exception) {
                    exception.printStackTrace();
                }
            }
        }
    }

然后,连接通道,发送数据。

address = new InetSocketAddress(ipAddress, 8088);
            flag = true;
            // 建立TCP连接通道

            thread = new Thread() {

                public void run() {
                    try {
                        tcpChannel = new TCPChannel(SocketChannel.open(),
                                address, 2);
                        tcpChannel.connect();
                        while (flag) {
                            LogUtil.e("while true循环着  去请求数据。。。。");
                            try {
                                tcpChannel.send(getSendData(1, 46));
                                sleep(500);
                                tcpChannel.send(getSendData(60, 10));

                                sleep(2500);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                                LogUtil.e("while 里抛出异常。");
                            }
                        }

                        LogUtil.e("tcp 请求数据,循环结束了。。。。。");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            };
            thread.start();

断网后,重新连接:

if (tcpChannel != null)
     tcpChannel.reConnect();

TCP连接就完毕了。之后是CRC16校验和byte数据处理。

更多相关文章

  1. [置顶] 使用BleLib的轻松搞定Android低功耗蓝牙Ble 4.0开发详解
  2. Android与PC的Socket(TCP/IP)通信(by USB) 拒绝连接的
  3. android数据存储
  4. Android(安卓)关于获取摄像头帧数据
  5. Android入门:SQLite
  6. android 数据存储
  7. Android(安卓)uevent
  8. Android短彩信数据库信息整理
  9. mybatisplus的坑 insert标签insert into select无参数问题的解决

随机推荐

  1. 子网掩码的进制转换
  2. vtp实验
  3. 共享文件夹
  4. 华为ensp链路聚合综合实验
  5. Kafka 原理以及分区分配策略剖析
  6. 单臂路由
  7. 说话时如何把“NO”变成“yes”?
  8. Azure DevTest Lab体验(二)用户测试
  9. 链路追踪 SkyWalking 源码分析 —— Coll
  10. 链路追踪 SkyWalking 源码分析 —— Coll