ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

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

2021-07-10 22:01:34  阅读:269  来源: 互联网

标签:String int 海明 校验 奇偶校验 add result new panel


一、结果截图

在这里插入图片描述在这里插入图片描述在这里插入图片描述

二、代码实现

代码分为四部分
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) + "%");

    }
}

标签:String,int,海明,校验,奇偶校验,add,result,new,panel
来源: https://blog.csdn.net/chigenb/article/details/118641273

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有