一、结果截图
二、代码实现
代码分为四部分
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) + "%");
}
}