Java实践(二)开TCP服务器接收客户端数据入库

一、实践目的

  • 先用java写一个tcp服务器,接收来自客户端的数据,解析入库mysql,为后续查库做准备。

二、步骤

在上一笔记中,开了tcp服务器将数据解析然后保存到txt文档,在这个基础上添加上mysql,库tcpdb1是由人手动创建,表由程序中检测自动创建个weathertable表,客户端发送数据后先检查帧尾和CRC校验,避免一些错误数据的输入,然后将未解析的数据按日、小时分文档保存到本地日志txt,将解析的数据自动入库,客户端发送的数据帧是自定了一个简单的数据格式。

写了4个class文件:
TCPService.class  :  程序的入口,开启tcp服务器
Parameter.class	  :  解析的参数
jdbc.class		  :  与数据库之间的操作
CRC16.class       :  crc16的数据校验

工程环境

1、需要添加jdbc,就是添加一个包(mysql-connector-java-5.1.37-bin.jar),类似库文件,能够使用java语句开发数据库,和mysql连接起来。
2、首先开个tcp服务器端口,使用ServiceSocke中accept一直监听,有客户端连接就开启一个线程,获取客户端发送的数据,检查数据帧尾和校验;
3、校验成功说明来的数据没问题,将数据做txt日志保存一下,按日份文件夹,按小时分文件,日志中记录数据接收时的时间;
4、保存完日志可以将整条数据分块解析了,创建个对象Para存起来,供入库时的参数输入;
5、参数值已经有了,现在可以入库,但这个库需要人工提前创建出来,一条创建库的语句就OK,这里起个库名叫tcpdb1,然后注册驱动(不注册也没关系,因为添加的jar包中已经注册过),获取数据库连接对象,定义sql语句,检查表是否已经创建过,不存在则创建,然后将解析的各个参数入库,释放资源。

Java实践(二)开TCP服务器接收客户端数据入库_第1张图片

三、结果

1、按日分文档,按小时分文件保存为txt日志

Java实践(二)开TCP服务器接收客户端数据入库_第2张图片

2、客户端发送数据,服务器解析数据,入库

Java实践(二)开TCP服务器接收客户端数据入库_第3张图片

四、代码

(1)TCPService.class(程序的入口,开启tcp服务器)

package com.ta.tcpsevice;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.lang.String;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.jar.JarOutputStream;
import java.util.zip.CRC32;

/*
 实现步骤:
        1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
        3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
        4.判断d:\\upload文件夹是否存在,不存在则创建
        5.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
        6.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件
        7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
        8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
        9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
        10.释放资源(FileOutputStream,Socket,ServerSocket)
 */
//#DATATIME=2019/7/10 13:26:46:123,SN=TG00001,TEMP=025.6C,RH=78%,PA=101.32kpa,WS=02.1m/s,WD=268,LO=121.9590627E,LA=036.9576059N,CRC=1C7F\r\n   发送过来的数据结尾\r\n是0d0a,测试校验时需要注意,校验到=
//程序中意外情况没有处理,数据末尾应该加个校验可减少意外数据
public class TCPService {
     
    public static void main(String[] args) throws IOException {
     
        System.out.println("服务端启动 , 等待连接 .... ");
        //1.创建一个服务器ServerSocket对象,和系统要指定的端口号
        ServerSocket server = new ServerSocket(6665);
        //2.使用ServerSocket对象中的方法accept,获取到请求的客户端Socket对象
        /*
            让服务器一直处于监听状态(死循环accept方法)
            有一个客户端上传文件,就保存一个文件
         */
        while(true){
     
            Socket socket = server.accept();
            /*
                使用多线程技术,提高程序的效率
                有一个客户端上传文件,就开启一个线程,完成文件的上传
             */
            new Thread(new Runnable() {
     
                //完成文件的上传
                @Override
                public void run() {
     
                    try {
     
                        System.out.println("客户端已连接");
                        //3.使用Socket对象中的方法getInputStream,获取到网络字节输入流InputStream对象
                        InputStream is = socket.getInputStream();

                        //4.使用网络字节输入流InputStream对象中的方法read,读取客户端上传的文件或数据
                        int len =0;
                        byte[] bytes = new byte[1024];
                        while((len = is.read(bytes))!=-1){
           //只要还存在数据或者来了新的数据
                            String GetStr=new String(bytes);     //收到的字符串

                            CRC16 crcClass=new CRC16();
                            int crcValue=crcClass.calcCrc16(bytes,0,len-6);//需注意这里的len,不要用bytes.length,去掉crc字符1c7f的4个字节,0d0a回车换行2个字节

                            int indexOfCRC=GetStr.indexOf("CRC=");     //获得第一个"DATETIME="的首地址位置 即“D”位置
                            String CRCStr=GetStr.substring(indexOfCRC+4,indexOfCRC+8); //根据第"D"后的位置,截取 字符串。
                            int CRC16StrValue= Integer.parseInt(CRCStr,16);//将字符串转换为16进制的数

                            if(bytes[len-2]==0x0D&&bytes[len-1]==0x0A&&len>20&&CRC16StrValue==crcValue)
                            {
     
                                System.out.println("接收到帧尾且数据校验通过");
                                /***存日志***/
                                SimpleDateFormat dfFolder = new SimpleDateFormat("yyyyMMdd");//设置日期格式
                                String folderName=dfFolder.format(new Date()).toString();
                                SimpleDateFormat dfFile = new SimpleDateFormat("yyyyMMddHH");//设置日期格式
                                String fileName=dfFile.format(new Date()).toString();
                                //5.判断文件夹是否存在,不存在则创建
                                File file =  new File("d:\\upload"+"\\"+folderName);
                                if(!file.exists()){
     
                                    file.mkdirs();
                                }
                                //6.创建一个本地字节输出流FileOutputStream对象,构造方法中绑定要输出的目的地
                                FileOutputStream fos = new FileOutputStream(file+"\\"+fileName+".txt",true);  //true追加数据
                                SimpleDateFormat dfDataCome = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");   //设置日期格式毫秒
                                String dataComeTime=dfDataCome.format(new Date()).toString()+" ";
                                //7.使用本地字节输出流FileOutputStream对象中的方法write,把读取到的文件保存到服务器的硬盘上
                                fos.write(dataComeTime.getBytes(),0,dataComeTime.length());
                                fos.write(GetStr.getBytes(),0,len);                                        //将接收到的数据存储日志文件,按年月日分文件夹,按日小时分文件存储
                                //fos.write("\r\n".getBytes());//写个换行
                                fos.close();
                                System.out.println("该条日志存储完毕");


                                /***解析入库***/
                                Parameter Para= new Parameter();
                                int indexOfDataTime=GetStr.indexOf("DATATIME=");     //获得第一个"DATETIME="的首地址位置 即“D”位置
                                String DataTimeStr=GetStr.substring(indexOfDataTime+9,indexOfDataTime+31); //根据第"D"后的位置,截取 字符串。
                                Para.setDatatime(DataTimeStr);

                                int indexOfSN=GetStr.indexOf("SN=");         //获得第一个"SN="的首地址位置 即“S”位置
                                String SNStr=GetStr.substring(indexOfSN+3,indexOfSN+10); //根据第"SN="后的位置,截取 字符串。
                                //index=bytes.toString().indexOf(",", index+1);//根据第一个"SN="的位置 获得第二个","的位置
                                Para.setSn(SNStr);

                                int indexOfTEMP=GetStr.indexOf("TEMP=");     //获得第一个""的首地址位置 即“”位置
                                String TEMPStr=GetStr.substring(indexOfTEMP+5,indexOfTEMP+10); //根据第""后的位置,截取 字符串。
                                Para.setAirtemperature(Double.parseDouble(TEMPStr));

                                int indexOfRH=GetStr.indexOf("RH=");     //获得第一个""的首地址位置 即“”位置
                                String RHStr=GetStr.substring(indexOfRH+3,indexOfRH+5); //根据第""后的位置,截取 字符串。
                                Para.setAirhumidity(Double.parseDouble(RHStr));

                                int indexOfPA=GetStr.indexOf("PA=");     //获得第一个""的首地址位置 即“”位置
                                String PAStr=GetStr.substring(indexOfPA+3,indexOfPA+9); //根据第""后的位置,截取 字符串。
                                Para.setAirpressure(Double.parseDouble(PAStr));

                                int indexOfWS=GetStr.indexOf("WS=");     //获得第一个""的首地址位置 即“”位置
                                String WSStr=GetStr.substring(indexOfWS+3,indexOfWS+7); //根据第""后的位置,截取 字符串。
                                Para.setWindspeed(Double.parseDouble(WSStr));

                                int indexOfWD=GetStr.indexOf("WD=");     //获得第一个""的首地址位置 即“”位置
                                String WDStr=GetStr.substring(indexOfWD+3,indexOfWD+6); //根据第""后的位置,截取 字符串。
                                Para.setWinddirection(Double.parseDouble(WDStr));

                                int indexOfLO=GetStr.indexOf("LO=");     //获得第一个""的首地址位置 即“”位置
                                String LOStr=GetStr.substring(indexOfLO+3,indexOfLO+15); //根据第""后的位置,截取 字符串。
                                Para.setLongitude(LOStr);

                                int indexOfLA=GetStr.indexOf("LA=");     //获得第一个""的首地址位置 即“”位置
                                String LAStr=GetStr.substring(indexOfLA+3,indexOfLA+15); //根据第""后的位置,截取 字符串。
                                Para.setLatitude(LAStr);

								jdbc.InsertDataToMySql(Para);//入库

                                System.out.println("数据写入完毕");
                                //8.使用Socket对象中的方法getOutputStream,获取到网络字节输出流OutputStream对象
                                //9.使用网络字节输出流OutputStream对象中的方法write,给客户端回写"上传成功"
                                socket.getOutputStream().write("Data upload successful!".getBytes());
                                //break;//既然数据都已经保存完毕,那就结束这次连接吧,如果想保持长连接就注释掉吧
                            }
                        }
                        System.out.println("断开连接");
                        //10.释放资源(FileOutputStream,Socket,ServerSocket)
                        socket.close();
                    }catch (IOException e){
     
                        System.out.println(e);
                    }
                }
            }).start();
        }
        //服务器就不用关闭
        //server.close();
    }
}

(2)jdbc.class(与数据库之间的操作)

package com.ta.tcpsevice;

import java.sql.*;

/**
 * JDBC快速入门
 */
public static class jdbc {
     
    //需要先手动创建一个数据库tcpdb1,库中的表及数据在程序中添加
    public void InsertDataToMySql(Parameter paravalue) {
     
        Connection conn = null;
        Statement stmt = null;
        try {
     
            //1. 导入驱动jar包
            //2.注册驱动
            Class.forName("com.mysql.jdbc.Driver");
            //3.获取数据库连接对象
            conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/tcpdb1", "root", "root");
            DatabaseMetaData meta = (DatabaseMetaData) conn.getMetaData();
            ResultSet set = meta.getTables(null, null, "weathertable", null);//weathertable为表名,看表是否存在
            if (set.next()) {
     
                System.out.println("表已存在");
            } else {
     
                System.out.println("创建表");
                //4.定义sql语句
                String sql = "CREATE TABLE weathertable " +
                        "(id INT PRIMARY KEY AUTO_INCREMENT," +
                        "datatime VARCHAR (30)," +
                        "sn VARCHAR (20)," +
                        "airtemperature DOUBLE," +
                        "airhumidity DOUBLE," +
                        "airpressure DOUBLE," +
                        "windspeed DOUBLE," +
                        "winddirection DOUBLE," +
                        "longitude VARCHAR (20),"+
                        "latitude VARCHAR (20)) ";
                //5.获取执行sql的对象 Statement
                stmt = conn.createStatement();
                //6.执行sql
                int count = stmt.executeUpdate(sql);
                //7.处理结果
                System.out.println(count);
            }
            set.close();//释放paravalue.getDatetime()
            String sql = "INSERT INTO weathertable " +
                    "(datatime," +
                    "sn," +
                    "airtemperature," +
                    "airhumidity," +
                    "airpressure," +
                    "windspeed," +
                    "winddirection," +
                    "longitude," +
                    "latitude" +
                    ")" +
                    "VALUES"+
                    "('"+paravalue.getDatatime()+"',"+
                    "'"+paravalue.getSn()+"',"+
                    paravalue.getAirtemperature()+","+
                    paravalue.getAirhumidity()+","+
                    paravalue.getAirpressure()+","+
                    paravalue.getWindspeed()+","+
                    paravalue.getWinddirection()+","+
                    "'"+paravalue.getLongitude()+"',"+
                    "'"+paravalue.getLatitude()+"');";

            //5.获取执行sql的对象 Statement
            stmt = conn.createStatement();
            //6.执行sql
            int count = stmt.executeUpdate(sql);
            //7.处理结果
            System.out.println(count);
            System.out.println("数据插入完成");

        } catch (ClassNotFoundException e) {
     
            e.printStackTrace();
        } catch (SQLException e) {
     
            e.printStackTrace();
        } finally {
     
            //7.释放资源
            if (stmt != null) {
     
                try {
     
                    stmt.close();
                } catch (SQLException e) {
     
                    e.printStackTrace();
                }
            }

            if (conn != null) {
     
                try {
     
                    conn.close();
                } catch (SQLException e) {
     
                    e.printStackTrace();
                }
            }
        }
    }
}

(3)Parameter.class(解析的参数)

package com.ta.tcpsevice;
/**
 * 封装参数列表
 */
public class Parameter {
     
    private String datatime;
    private String sn;
    private double airtemperature;
    private double airhumidity;
    private double airpressure;
    private double windspeed;
    private double winddirection;
    private String longitude;
    private String latitude;


    public String getDatatime() {
     
        return datatime;
    }

    public void setDatatime(String datatime) {
     
        this.datatime = datatime;
    }

    public String getSn() {
     
        return sn;
    }

    public void setSn(String sn) {
     
        this.sn = sn;
    }

    public double getAirtemperature() {
     
        return airtemperature;
    }

    public void setAirtemperature(double airtemperature) {
     
        this.airtemperature = airtemperature;
    }

    public double getAirhumidity() {
     
        return airhumidity;
    }

    public void setAirhumidity(double airhumidity) {
     
        this.airhumidity = airhumidity;
    }

    public double getAirpressure() {
     
        return airpressure;
    }

    public void setAirpressure(double airpressure) {
     
        this.airpressure = airpressure;
    }

    public double getWindspeed() {
     
        return windspeed;
    }

    public void setWindspeed(double windspeed) {
     
        this.windspeed = windspeed;
    }

    public double getWinddirection() {
     
        return winddirection;
    }

    public void setWinddirection(double winddirection) {
     
        this.winddirection = winddirection;
    }

    public String getLongitude() {
     
        return longitude;
    }

    public void setLongitude(String longitude) {
     
        this.longitude = longitude;
    }

    public String getLatitude() {
     
        return latitude;
    }

    public void setLatitude(String latitude) {
     
        this.latitude = latitude;
    }
}

(4)CRC16.class(crc16的数据校验)

package com.ta.tcpsevice;

public class CRC16 {
     
    static byte[] crc16_tab_h = {
      (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1,
            (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0,
            (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x01, (byte) 0xC0, (byte) 0x80, (byte) 0x41, (byte) 0x00, (byte) 0xC1, (byte) 0x81, (byte) 0x40 };

    static byte[] crc16_tab_l = {
      (byte) 0x00, (byte) 0xC0, (byte) 0xC1, (byte) 0x01, (byte) 0xC3, (byte) 0x03, (byte) 0x02, (byte) 0xC2, (byte) 0xC6, (byte) 0x06, (byte) 0x07, (byte) 0xC7, (byte) 0x05, (byte) 0xC5, (byte) 0xC4, (byte) 0x04, (byte) 0xCC, (byte) 0x0C, (byte) 0x0D, (byte) 0xCD, (byte) 0x0F, (byte) 0xCF, (byte) 0xCE, (byte) 0x0E, (byte) 0x0A, (byte) 0xCA, (byte) 0xCB, (byte) 0x0B, (byte) 0xC9, (byte) 0x09, (byte) 0x08, (byte) 0xC8, (byte) 0xD8, (byte) 0x18, (byte) 0x19, (byte) 0xD9, (byte) 0x1B, (byte) 0xDB, (byte) 0xDA, (byte) 0x1A, (byte) 0x1E, (byte) 0xDE, (byte) 0xDF, (byte) 0x1F, (byte) 0xDD, (byte) 0x1D, (byte) 0x1C, (byte) 0xDC, (byte) 0x14, (byte) 0xD4, (byte) 0xD5, (byte) 0x15, (byte) 0xD7, (byte) 0x17, (byte) 0x16, (byte) 0xD6, (byte) 0xD2, (byte) 0x12,
            (byte) 0x13, (byte) 0xD3, (byte) 0x11, (byte) 0xD1, (byte) 0xD0, (byte) 0x10, (byte) 0xF0, (byte) 0x30, (byte) 0x31, (byte) 0xF1, (byte) 0x33, (byte) 0xF3, (byte) 0xF2, (byte) 0x32, (byte) 0x36, (byte) 0xF6, (byte) 0xF7, (byte) 0x37, (byte) 0xF5, (byte) 0x35, (byte) 0x34, (byte) 0xF4, (byte) 0x3C, (byte) 0xFC, (byte) 0xFD, (byte) 0x3D, (byte) 0xFF, (byte) 0x3F, (byte) 0x3E, (byte) 0xFE, (byte) 0xFA, (byte) 0x3A, (byte) 0x3B, (byte) 0xFB, (byte) 0x39, (byte) 0xF9, (byte) 0xF8, (byte) 0x38, (byte) 0x28, (byte) 0xE8, (byte) 0xE9, (byte) 0x29, (byte) 0xEB, (byte) 0x2B, (byte) 0x2A, (byte) 0xEA, (byte) 0xEE, (byte) 0x2E, (byte) 0x2F, (byte) 0xEF, (byte) 0x2D, (byte) 0xED, (byte) 0xEC, (byte) 0x2C, (byte) 0xE4, (byte) 0x24, (byte) 0x25, (byte) 0xE5, (byte) 0x27, (byte) 0xE7,
            (byte) 0xE6, (byte) 0x26, (byte) 0x22, (byte) 0xE2, (byte) 0xE3, (byte) 0x23, (byte) 0xE1, (byte) 0x21, (byte) 0x20, (byte) 0xE0, (byte) 0xA0, (byte) 0x60, (byte) 0x61, (byte) 0xA1, (byte) 0x63, (byte) 0xA3, (byte) 0xA2, (byte) 0x62, (byte) 0x66, (byte) 0xA6, (byte) 0xA7, (byte) 0x67, (byte) 0xA5, (byte) 0x65, (byte) 0x64, (byte) 0xA4, (byte) 0x6C, (byte) 0xAC, (byte) 0xAD, (byte) 0x6D, (byte) 0xAF, (byte) 0x6F, (byte) 0x6E, (byte) 0xAE, (byte) 0xAA, (byte) 0x6A, (byte) 0x6B, (byte) 0xAB, (byte) 0x69, (byte) 0xA9, (byte) 0xA8, (byte) 0x68, (byte) 0x78, (byte) 0xB8, (byte) 0xB9, (byte) 0x79, (byte) 0xBB, (byte) 0x7B, (byte) 0x7A, (byte) 0xBA, (byte) 0xBE, (byte) 0x7E, (byte) 0x7F, (byte) 0xBF, (byte) 0x7D, (byte) 0xBD, (byte) 0xBC, (byte) 0x7C, (byte) 0xB4, (byte) 0x74,
            (byte) 0x75, (byte) 0xB5, (byte) 0x77, (byte) 0xB7, (byte) 0xB6, (byte) 0x76, (byte) 0x72, (byte) 0xB2, (byte) 0xB3, (byte) 0x73, (byte) 0xB1, (byte) 0x71, (byte) 0x70, (byte) 0xB0, (byte) 0x50, (byte) 0x90, (byte) 0x91, (byte) 0x51, (byte) 0x93, (byte) 0x53, (byte) 0x52, (byte) 0x92, (byte) 0x96, (byte) 0x56, (byte) 0x57, (byte) 0x97, (byte) 0x55, (byte) 0x95, (byte) 0x94, (byte) 0x54, (byte) 0x9C, (byte) 0x5C, (byte) 0x5D, (byte) 0x9D, (byte) 0x5F, (byte) 0x9F, (byte) 0x9E, (byte) 0x5E, (byte) 0x5A, (byte) 0x9A, (byte) 0x9B, (byte) 0x5B, (byte) 0x99, (byte) 0x59, (byte) 0x58, (byte) 0x98, (byte) 0x88, (byte) 0x48, (byte) 0x49, (byte) 0x89, (byte) 0x4B, (byte) 0x8B, (byte) 0x8A, (byte) 0x4A, (byte) 0x4E, (byte) 0x8E, (byte) 0x8F, (byte) 0x4F, (byte) 0x8D, (byte) 0x4D,
            (byte) 0x4C, (byte) 0x8C, (byte) 0x44, (byte) 0x84, (byte) 0x85, (byte) 0x45, (byte) 0x87, (byte) 0x47, (byte) 0x46, (byte) 0x86, (byte) 0x82, (byte) 0x42, (byte) 0x43, (byte) 0x83, (byte) 0x41, (byte) 0x81, (byte) 0x80, (byte) 0x40 };

    /**
     * 计算CRC16校验
     *
     * @param data
     *            需要计算的数组
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data) {
     
        return calcCrc16(data, 0, data.length);
    }

    /**
     * 计算CRC16校验
     *
     * @param data
     *            需要计算的数组
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data, int offset, int len) {
     
        return calcCrc16(data, offset, len, 0xffff);
    }

    /**
     * 计算CRC16校验
     *
     * @param data
     *            需要计算的数组
     * @param offset
     *            起始位置
     * @param len
     *            长度
     * @param preval
     *            之前的校验值
     * @return CRC16校验值
     */
    public static int calcCrc16(byte[] data, int offset, int len, int preval) {
     
        int ucCRCHi = (preval & 0xff00) >> 8;
        int ucCRCLo = preval & 0x00ff;
        int iIndex;
        for (int i = 0; i < len; ++i) {
     
            iIndex = (ucCRCLo ^ data[offset + i]) & 0x00ff;
            ucCRCLo = ucCRCHi ^ crc16_tab_h[iIndex];
            ucCRCHi = crc16_tab_l[iIndex];
        }
        return ((ucCRCHi & 0x00ff) << 8) | (ucCRCLo & 0x00ff) & 0xffff;
    }

	// 测试
	public static void main(String[] args) {
     
		// 0x02 05 00 03 FF 00 , crc16=7C 09
		int crc = CRC16.calcCrc16(new byte[] {
      0x02, 0x05, 0x00, 0x03, (byte) 0xff, 0x00 });
		System.out.println(String.format("0x%04x", crc));
	}

}

你可能感兴趣的:(java)