奇偶校验、海明校验、CRC校验——可视化实现

一、结果截图

奇偶校验、海明校验、CRC校验——可视化实现奇偶校验、海明校验、CRC校验——可视化实现奇偶校验、海明校验、CRC校验——可视化实现

二、代码实现

代码分为四部分
1、Main1.java

import java.awt.*;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;

public class Main1 {

    public static void main(String[] args) {
        JTabbedPane tabbedPane;
        tabbedPane = new JTabbedPane();

        ParityPanel panel = new ParityPanel();
        panel.table.setModel(new DefaultTableModel(panel.rowData, panel.cNames));
        panel.table.setRowHeight(30);
        panel.west.add(panel.scrollPane);
        panel.add(panel.west);
        panel.table1.setModel(new DefaultTableModel(panel.rowData1, panel.cNames1));
        ParityPanel.setColor(panel.table1,panel.getColor());
        panel.table1.setRowHeight(30);
        panel.east.add(panel.scrollPane1);
        panel.add(panel.east);
        panel.send.addActionListener(panel);
        panel.add(panel.send);
        JPanel jp3 = new JPanel(new BorderLayout());
        JPanel jp2 = new JPanel();
        panel.text2.setText(String.valueOf(100-panel.error));
        panel.text3.setText(String.valueOf(panel.error));
        panel.text4.setText(String.valueOf(panel.noCheckOut));
        panel.text5.setText(String.valueOf(panel.error+panel.noCheckOut)+"%");
        jp2.add(panel.label1);
        jp2.add(panel.text1);
        jp2.add(panel.label2);
        jp2.add(panel.text2);
        jp2.add(panel.label3);
        jp2.add(panel.text3);
        jp2.add(panel.label4);
        jp2.add(panel.text4);
        jp2.add(panel.label5);
        jp2.add(panel.text5);
        jp3.add(panel, "Center");
        jp3.add(jp2, "South");
        tabbedPane.addTab("奇偶校验", jp3);

        HammingPanel panel1 = new HammingPanel();
        panel1.add(panel1.textArea);
        panel1.add(panel1.button);
        panel1.add(panel1.textArea1);
        panel1.add(panel1.textArea2);
        panel1.add(panel1.button1);
        panel1.add(panel1.textArea3);
        panel1.add(panel1.button2);
        panel1.add(panel1.textArea4);
        panel1.add(panel1.button3);
        panel1.add(panel1.textArea5);
        panel1.button.addActionListener(panel1);
        tabbedPane.addTab("海明码校验", panel1);


        CRCPanel panel2 = new CRCPanel();
        panel2.add(panel2.textArea);
        panel2.add(panel2.textArea1);
        panel2.add(panel2.button);
        panel2.add(panel2.textArea2);
        panel2.add(panel2.textArea3);
        panel2.add(panel2.button1);
        panel2.add(panel2.textArea4);
        panel2.add(panel2.button2);
        panel2.add(panel2.textArea5);
        panel2.button.addActionListener(panel2);
        tabbedPane.addTab("CRC校验", panel2);



        tabbedPane.setPreferredSize(new Dimension(430, 340));
        tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
        tabbedPane.setTabPlacement(JTabbedPane.TOP);
        JFrame frame = new JFrame("数据安全性实验");
        frame.add(tabbedPane);
        frame.setContentPane(tabbedPane);
        Toolkit kit = Toolkit.getDefaultToolkit();
        Dimension screen = kit.getScreenSize();
        int x = screen.width;
        int y = screen.height;
        int xcenter = (x-1000) / 2;
        int ycenter = (y-600) / 2;
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(1000 , 600);
        frame.setLocation(xcenter,ycenter );
        frame.setVisible(true);
    }
}

2、CRCPanel.java

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;

public class CRCPanel extends JPanel implements ActionListener{
    JTextField textArea = new JTextField(18);
    JTextField textArea1 = new JTextField(18);
    JButton button = new JButton("计算校验位");

    JTextField textArea2 = new JTextField(18);
    JTextField textArea3 = new JTextField(18);

    JButton button1 = new JButton("接收到的数据");
    JTextField textArea4 = new JTextField(18);
    JButton button2 = new JButton("是否出错");
    JTextField textArea5 = new JTextField(18);

    String crc = "";
    String crcAll = "";

    public String getDisruptedData(String data) {
        int probability = new Random().nextInt(20); //设计出错率1/2
        int index = new Random().nextInt(7);
        StringBuilder stringBuilder = new StringBuilder(data);
        if (probability < 10) {
            if (data.charAt(index) == '0') {
                stringBuilder.setCharAt(index, '1');
            }
            else {
                stringBuilder.setCharAt(index, '0');
            }
        }
        return stringBuilder.toString();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        crc(textArea.getText(), textArea1.getText());
        textArea2.setText(this.crc);
        textArea3.setText(this.crcAll);

        String result = getDisruptedData(this.crcAll.toString());
        textArea4.setText(result);

        //计算2的sum-1次幂,并将2的sum-1次幂转换为int型
        BigInteger bi = new BigInteger("2");
        int flag = bi.pow(this.crcAll.length()-1).intValue();

        int gx = Integer.parseInt(textArea1.getText(),2);
        gx = gx<<(this.crcAll.length()-textArea1.getText().length());

        int data = Integer.parseInt(result,2);
        for(int i=0; i<(this.crcAll.length()-textArea1.getText().length()+1);i++){
            //判断补零后的帧最高位为1还是零
            if((data&flag)!=0) {
                data = data^gx;
                gx = gx>>1;
            }else {
                gx = gx>>1;
            }
            //flag最高位的1右移
            flag = flag>>1;
        }
        String crc = Integer.toBinaryString(data);
        //解决Java输出二进制时略去高位零的问题
        while(crc.length()<(textArea1.getText().length()-1)) {
            crc = "0"+crc;
        }
        if(crc.equals("000"))
            textArea5.setText("正确");
        else
            textArea5.setText("错误");

    }

    public String crc(String dataStr,String gxStr) {
            //获取二进制帧的位数
            int dataStrLen = dataStr.length();
            //获取多项式位数
            int gxStrLen = gxStr.length();
            //将二进制的字符串变为整型
            int data = Integer.parseInt(dataStr,2);
            //将多项式的字符串变为整型
            int gx = Integer.parseInt(gxStr,2);
            //算出原始数据补零后的总位数
            int sum = dataStrLen+gxStrLen-1;
            //计算2的sum-1次幂,并将2的sum-1次幂转换为int型
            BigInteger bi = new BigInteger("2");
            int flag = bi.pow(sum-1).intValue();
            //原始帧低位补零
            data = data<<(gxStrLen-1);
            //多项式低位补零,使其与补零后的帧位数一致,以便异或
            gx = gx<<(dataStrLen-1);
            //循环dataStrLen次
            for(int i=0; i<(dataStrLen);i++){
                //判断补零后的帧最高位为1还是零
                if((data&flag)!=0) {
                    data = data^gx;
                    gx = gx>>1;
                }else {
                    gx = gx>>1;
                }
                //flag最高位的1右移
                flag = flag>>1;
            }
            String crc = Integer.toBinaryString(data);
            //解决Java输出二进制时略去高位零的问题
            while(crc.length()<(gxStrLen-1)) {
                crc = "0"+crc;
            }
            this.crc = crc;
            this.crcAll = textArea.getText()+crc;
            return crc;
        }
}

3、HammingPanel.java

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class HammingPanel extends JPanel implements ActionListener {
    JTextField textArea = new JTextField(18);
    JButton button = new JButton("计算校验位");
    JTextField textArea1 = new JTextField(18);
    JTextField textArea2 = new JTextField(18);

    JButton button1 = new JButton("接收到的数据");
    JTextField textArea3 = new JTextField(18);
    JButton button2 = new JButton("是否出错");
    JTextField textArea4 = new JTextField(18);

    JButton button3 = new JButton("纠正");
    JTextField textArea5 = new JTextField(18);

    byte[] finalary;
    byte[] ver;

    /**
     * 接收信息码
     * 计算校验码
     * 合并为海明码
     * */
    public byte[] hmCode(String src) {
        /*
         * 第一步先确定需要多少位校验码。
         * 设数据有n位,校验码有x位。则校验码一共有2^x种取值方式。
         * 其中需要一种取值方式表示数据正确,剩下2^x−1种取值方式表示有一位数据出错。
         * 因为编码后的二进制串有n+x位,因此x应该满足:2^x>=n+x+1
         * 使不等式成立的x的最小值就是校验码的位数
         */
        String[] source = src.split("");//将信息码逐位分开并存进数组
        int n = source.length;
        int x = 0;
        while ((1 << x) < n + x + 1) x++;//确定x值,即校验位位数

        byte[] finalary = new byte[n + x];//申请数存放最终数据的数组

        /*
         * 校验码在二进制串中的位置为2的整数幂,即1、2、4、8、16……..剩下的位置是信息码
         */
        int[] index = new int[x];//记录校验码的位置
        for (int i = 0, j = 0, point = 0, in = 0; i < finalary.length; i++) {
            if (1 << j == i + 1 && j <= x) {
                j++;
                index[in++] = i;
            } else {
                if (point < n) {
                    finalary[i] = Byte.parseByte(source[point++]);//先将信息码填进finalary[]
                }
            }
        }

        /*
         * 由于奇偶校验原理一样,偶校验的计算更为简单,实际中多用偶校验
         */
        byte[] ver = new byte[x];//记录校验位的值
        for (int p = 0; p < x; p++) {
            int verification = 0;
            for (int i = 1 << p; i <= finalary.length; i++) {
                if (((i >> p) & 1) == 1) {
                    verification = verification ^ finalary[i - 1];
                }
            }
            ver[p] = (byte) (verification == 0 ? 0 : 1);
        }

        /*
         * 校验码填进校验位
         */
        for (int i = 0; i < x; i++) {
            finalary[index[i]] = ver[i];
        }
        this.ver = ver;
        this.finalary = finalary;
        return finalary;
    }

    /**
     * 设计出错率1/2,一旦出错就变一位
     * */
    public String getDisruptedData(String data) {
        int probability = new Random().nextInt(20); //设计出错率1/2
//        int index = 3;
        int index = new Random().nextInt(7);
        StringBuilder stringBuilder = new StringBuilder(data);
        if (probability < 10) {
            if (data.charAt(index) == '0') {
                stringBuilder.setCharAt(index, '1');
            } else {
                stringBuilder.setCharAt(index, '0');
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 设计List异或运算
     * */
    public String xor(List<Character> list) {
        int count = 0;

        for (char c : list) {
            if (c == 49) {//在ascii表中,49代表数字1
                count += 1;
            }
        }
        if (count % 2 == 0) {//偶数个1的异或结果是0
            return "0";
        }
        return "1";

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        hmCode(textArea.getText());
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < this.ver.length; i++) {
            stringBuilder.append(ver[i]);
        }
        StringBuilder stringBuilder1 = new StringBuilder();
        for (int i = 0; i < this.finalary.length; i++) {
            stringBuilder1.append(finalary[i]);
        }
        textArea1.setText(stringBuilder.toString());
        textArea2.setText(stringBuilder1.toString());

        String result = getDisruptedData(stringBuilder1.toString());


        textArea3.setText(result);
        List<String> numbers = new ArrayList<>();
        List<Character> g1 = new ArrayList<>();

        g1.add(result.charAt(0));
        g1.add(result.charAt(2));
        g1.add(result.charAt(4));
        g1.add(result.charAt(6));
        g1.add(result.charAt(8));
        g1.add(result.charAt(10));


        List<Character> g2 = new ArrayList<>();
        g2.add(result.charAt(1));
        g2.add(result.charAt(2));
        g2.add(result.charAt(5));
        g2.add(result.charAt(6));
        g2.add(result.charAt(9));
        g2.add(result.charAt(10));

        List<Character> g3 = new ArrayList<>();
        g3.add(result.charAt(3));
        g3.add(result.charAt(4));
        g3.add(result.charAt(5));
        g3.add(result.charAt(6));
        g3.add(result.charAt(11));

        List<Character> g4 = new ArrayList<>();
        g4.add(result.charAt(7));
        g4.add(result.charAt(8));
        g4.add(result.charAt(9));
        g4.add(result.charAt(10));
        g4.add(result.charAt(11));
        numbers.add(xor(g4));
        numbers.add(xor(g3));
        numbers.add(xor(g2));
        numbers.add(xor(g1));

        int rest = 0;
        if (numbers.get(0) == "1") {
            rest += 8;
        }
        if (numbers.get(1) == "1") {
            rest += 4;
        }
        if (numbers.get(2) == "1") {
            rest += 2;
        }
        if (numbers.get(3) == "1") {
            rest += 1;
        }
        if (numbers.contains("1")) {
            textArea4.setText("错误");
        } else {
            textArea4.setText("正确");
        }
        String[] source = result.split("");
        String fixString = "";
        if (rest != 0) {
            for (int i = 0; i < result.length(); i++) {
                if (i == rest - 1) {
                    if (source[i].equals("0")) {
                        source[i] = "1";
                        break;
                    }
                    if (source[i].equals("1")) {
                        source[i] = "0";
                        break;
                    }
                }
            }
            for (int i = 0; i < source.length; i++) {
                fixString += source[i];
            }
            textArea5.setText(fixString);
        }
    }
}

4、ParityPanel.java

import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

public class ParityPanel extends JPanel implements ActionListener {
    JPanel west = new JPanel(new FlowLayout());
    JPanel east = new JPanel(new FlowLayout());
    int error = 0;
    int noCheckOut = 0;

    JLabel label1 = new JLabel("共传数据(组):");
    JLabel label2 = new JLabel("检验通过数据:");
    JLabel label3 = new JLabel("出错数据:");
    JLabel label4 = new JLabel("未检出数据:");
    JLabel label5 = new JLabel("传输错误率:");

    JLabel text1 = new JLabel("100");
    JLabel text2 = new JLabel();
    JLabel text3 = new JLabel();
    JLabel text4 = new JLabel();
    JLabel text5 = new JLabel();

    Color[] colors = new Color[100];

    String[] cNames = {"序号", "信息项", "校验码"};
    String[] cNames1 = {"序号", "信息项", "校验码", "计算"};
    Object[][] rowData = getRdata();//左边
    Object[][] rowData1 = getRdata1();//右边

    JTable table = new JTable();
    JTable table1 = new JTable();
    JScrollPane scrollPane = new JScrollPane(table);
    JScrollPane scrollPane1 = new JScrollPane(table1);
    JButton send = new JButton("产生数据");

    /**
     * 生成左边的数据
     * */
    public Object[][] getRdata() { //100个随机数
        Integer[] data = new Integer[100];
        String[] dataString = new String[100];
        for (int i = 0; i < 100; i++) {
            data[i] = new Random().nextInt(255);//生成十进制随机数
            dataString[i] = toBinary(data[i], 8);//转化为二进制
        }
        Object[][] objectArray = new Object[100][3];
        for (int i = 0; i < 100; i++) {
            objectArray[i][0] = i + 1; //序号
            objectArray[i][1] = dataString[i];
            objectArray[i][2] = getCheckCode(dataString[i]);
        }
        return objectArray;
    }

    /**
     * 生成右边的数据
     * */
    public Object[][] getRdata1() {
        Object[][] objectArray = new Object[100][4];
        for (int i = 0; i < 100; i++) {
            objectArray[i][0] = i + 1;
            objectArray[i][1] = getDisruptedData((String) rowData[i][1]);//接收到的数据
            objectArray[i][2] = rowData[i][2];
            objectArray[i][3] = getCheckCode((String) objectArray[i][1]); //计算接收数据的校验位
        }
        return objectArray;
    }



    /**
     * 设计出错率1/10,一旦出错就变两位
     * */
    public String getDisruptedData(String data) {
        int probability = new Random().nextInt(99); //设计出错率1/10
        int index = new Random().nextInt(7);
        int index1 = new Random().nextInt(7);
        StringBuilder stringBuilder = new StringBuilder(data);
        if (probability < 10) {                            //设计出错率1/10,一旦出错就变两位
            if (data.charAt(index) == '0') {
                stringBuilder.setCharAt(index, '1');
            } else {
                stringBuilder.setCharAt(index, '0');
            }

            if (data.charAt(index1) == '0') {
                stringBuilder.setCharAt(index1, '1');
            } else {
                stringBuilder.setCharAt(index1, '0');
            }
        }
        return stringBuilder.toString();
    }

    /**
     *将0~255的十进制数转换成8位的二进制
     * */
    public static String toBinary(int num, int digits) {
        int value = 1 << digits | num;//num的第一位可能是0,如果直接Integer.toBinaryString(num)会导致num变成7位,所以先按此行这样变成9位,在return时返回后8位
        String bs = Integer.toBinaryString(value); //0x20 | 这个是为了保证这个string长度是6位数
        return bs.substring(1);
    }

    /**
     * 采用偶校验,如果有奇数个1,校验位就设置为1,否则设置为0
     * */
    public static int getCheckCode(String data) {
        int count = 0;
        for (int i = 0; i < data.length(); i++) {
            if ('1' == data.charAt(i)) {
                count++;
            }
        }
        return isOdd(count) ? 1 : 0;
    }

    /**
     * 判断是否是奇数
     * */
    public static boolean isOdd(int a) {
        if ((a & 1) == 1) {
            return true;
        }
        return false;
    }

    /**
     * 按数据分类获取颜色
     * */
    public Color[] getColor() {
        int num1 = 0;
        int num2 = 0;
        Color[] colors = new Color[100];
        for (int i = 0; i < 100; i++) {
            String a = (String) rowData[i][1];
            String b = (String) rowData1[i][1];
            String c = String.valueOf(rowData1[i][2]);
            String d = String.valueOf(rowData1[i][3]);
            if (a.equals(b)) {
                colors[i] = Color.BLACK;
            } else {
                if (c.equals(d)) {
                    num2++;
                    colors[i] = Color.GREEN;
                } else {
                    num1++;
                    colors[i] = Color.RED;
                }
            }
        }
        error = num1;
        noCheckOut = num2;
        return colors;
    }

    /**
     * 按数据分类标记颜色
     * */
    public static void setColor(JTable table, Color[] color) {
        try {
            DefaultTableCellRenderer dtcr = new DefaultTableCellRenderer() {
                //重写getTableCellRendererComponent 方法
                @Override
                public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
                    setForeground(color[row]);
                    return super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
                }
            };
            //对每行的每一个单元格
            int columnCount = table.getColumnCount();
            for (int i = 0; i < columnCount; i++) {
                table.getColumn(table.getColumnName(i)).setCellRenderer(dtcr);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 点击button后执行
     * */
    @Override
    public void actionPerformed(ActionEvent e) {
        rowData = getRdata();
        table.setModel(new DefaultTableModel(rowData, cNames));
        rowData1 = getRdata1();
        table1.setModel(new DefaultTableModel(rowData1, cNames1));
        setColor(table1, getColor());
        text2.setText(String.valueOf(100 - error));
        text3.setText(String.valueOf(error));
        text4.setText(String.valueOf(noCheckOut));
        text5.setText(String.valueOf(error + noCheckOut) + "%");

    }
}
上一篇:panel 面板


下一篇:51单片机—串口通信