循環冗余校驗碼
CRC碼利用生成多項式為k個數據位產生r個校驗位進行編碼,其編碼長度為n=k+r所以又稱 (n,k)碼. CRC碼廣泛應用於數據通信領域和磁介質存儲系統中. CRC理論非常復雜,一般書就給個例題,講講方法.現在簡單介紹下它的原理:
在k位信息碼后接r位校驗碼,對於一個給定的(n,k)碼。可以證明(數學高手自己琢磨證明過程)存在一個最高次冪為 n-k=r 的多項式g(x),根據g(x)可以生成k位信息的校驗碼,g(x)被稱為 生成多項式
用C(x)=C(k-1)C(k-2)...C0表示k個信息位,把C(x)左移r位,就是相當於 C(x)*pow(2,r) 給校驗位空出r個位來了.給定一個 生成多項式g(x),可以求出一個校驗位表達式r(x) 。C(x)*pow(2,r) / g(x) = q(x) + r(x)/g(x) 用C(x)*pow(2,r)去除生成多項式g(x)商為q(x)余數是r(x)。所以有C(x)*pow(2,r) = q(x)*g(x) + r(x)。
C(x)*pow(2,r) + r(x)就是所求的n位CRC碼,由上式可以看出它是生成多項式g(x)的倍式.所以如果用得到的n位CRC碼去除g(x)如果余數是0,就證明數據正確. 否則可以根據余數知道出錯位.
在CRC運算過程中,四則運算采用 mod 2運算(后面介紹),即不考慮進位和借位. 所以上式等價於C(x)*pow(2,r) + r(x) = q(x)*g(x)
繼續前先說下基本概念吧.
1.多項式和二進制編碼
x的最高次冪位對應二進制數的最高位.以下各位對應多項式的各冪次. 有此冪次項為1,無為0. x的最高冪次為r時, 對應的二進制數有r+1位 例如g(x)=pow(x,4) + pow(x,3) + x + 1 對應二進制編碼是 11011
2.生成多項式是發送方和接受方的一個約定,也是一個二進制數,在整個傳輸過程中,這個數不會變.
在發送方利用 生成多項式 對信息多項式做模2運算生成校驗碼.
在接受方利用 生成多項式 對收到的 編碼多項式 做模2運算校驗和糾錯.
生成多項式應滿足:
a.生成多項式的最高位和最低位必須為1
b.當信息任何一位發生錯誤時,被生成多項式模2運算后應該使余數不為0
c.不同位發生錯誤時,應該使余數不同.
d.對余數繼續做模2除,應使余數循環.
生成多項式很復雜,不過不用我們生成。
下面給出一些常用的生成多項式表
n k 二進制碼(自己根據多項式和二進制編碼 的介紹轉)
7 4 1011 或 1101
7 3 11011 或 10111
15 11 1011
31 26 100101
3.模2運算
a.加減法法則
0 +/- 0 = 0
0 +/- 1 = 1
1 +/- 0 = 1
1 +/- 1 = 0
注意:沒有進位和借位
b.乘法法則
利用模2加求部分積之和,沒有進位
c.除法法則
利用模2減求部分余數,沒有借位,每商1位則部分余數減1位,余數最高位是1就商1,不是就商0,當部分余數的位數小於余數時,該余數就是最后余數.
例 1110
1011)1100000
1011
1110
1011
1010
1011
0010(每商1位則部分余數減1位,所以前兩個0寫出)
0000
010(當部分余數的位數小於余數時,該余數就是最后余數)
最后商是1110余數是010
好了說了那么多沒用的理論.下面講下CRC的實際應用.例: 給定的生成多項式g(x)=1011, 用(7,4)CRC碼對C(x)=1010進行編碼.
由題目可以知道下列的信息:
C(x)=1010,n=7,k=4,r=3,g(x)=1011 C(x)*pow(2,3)=1010000 C(x)*pow(2,3) / g(x) = 1001 + 11/1011 所以r(x)=011.所以要求的編碼為1010011
例2: 上題中,數據傳輸后變為1000011,試用糾錯機制糾錯. 1000011 / g(x) = 1011 + 110/1011
不能整除,所以出錯了. 因為余數是110.查1011出錯位表可以知道是第5位出錯.對其求反即可.
冗余碼的計算方法是,先將信息碼后面補0,補0的個數是生成多項式最高次冪;將補零之后的信息碼除以G(X),注意除法過程中所用的減法是模2減法,即沒有借位的減法,也就是異或運算。當被除數逐位除完時,得到比除數少一位的余數。此余數即為冗余位,將其添加在信息位后便構成CRC碼字。
例如,假設信息碼字為11100011,生成多項式G(X)=X^5+X^4+X+1,計算CRC碼字。
G(X) = X^5+X^4+X+1,也就是110011,因為最高次是5,所以,在信息碼字后補5個0,變為1110001100000。用1110001100000除以110011,余數為11010,即為所求的冗余位。
因此發送出去的CRC碼字為原始碼字11100011末尾加上冗余位11010,即 1110001111010。接收端收到碼字后,采用同樣的方法驗證,即將收到的碼字除以G(X),發現余數是0,則認為碼字在傳輸過程中沒有出錯。

package com.hjzgg.crc; import java.util.ArrayList; public class CrcCheck { /* CRC-4 x4+x+1 3 ITU G.704 CRC-8 x8+x5+x4+1 0x31 CRC-8 x8+x2+x1+1 0x07 CRC-8 x8+x6+x4+x3+x2+x1 0x5E CRC-12 x12+x11+x3+x+1 80F CRC-16 x16+x15+x2+1 8005 IBM SDLC CRC16-CCITT x16+x12+x5+1 1021 ISO HDLC, ITU X.25, V.34/V.41/V.42, PPP-FCS CRC-32 x32+x26+x23+...+x2+x+1 04C11DB7 ZIP, RAR, IEEE 802 LAN/FDDI, IEEE 1394, PPP-FCS CRC-32c x32+x28+x27+...+x8+x6+1 1EDC6F41 SCTP */ public static final String[] polynomeMsg = {"CRC-4 : x4+x+1", "CRC-8 : x8+x5+x4+1", "CRC-8 : x8+x2+x1+1", "CRC-8 : x8+x6+x4+x3+x2+x1", "CRC-12 : x12+x11+x3+x+1", "CRC-16 : x16+x15+x2+1", "CRC16-CCITT : x16+x12+x5+1", "CRC-32 : x32+x26+x23+...+x2+x+1", "CRC-32c : x32+x28+x27+...+x8+x6+1"}; private final int bits[] = {4,8,8,8,12,16,16,32,32}; private int polynomeChoose = 0; private String msg = null; public String getMsg(){ return msg; } public int getPolynomeChoose() { return polynomeChoose; } public void setPolynomeChoose(int polynomeChoose) { this.polynomeChoose = polynomeChoose; } private static final int[] polynome = {0x3, 0x31, 0x07, 0x5E, 0x80F, 0x8005, 0x1021, 0x04C11DB7, 0x1EDC6F41}; public void toCrcCode(ArrayList<Integer> code){ msg = "信息源碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); int poly = polynome[polynomeChoose];//選擇的多項式 int r = bits[polynomeChoose]-1;//多項式的位數 for(int i=1; i<=r; ++i)//將原信息擴大 r-1 位,用來填充校驗碼 code.add(0); int crc = 0;//余數 int highBit = 1<<r;//獲取crc的最高位 poly |= highBit; for(int i=0; i<code.size(); ++i){ crc |= code.get(i); if((crc&highBit) != 0)//最高位如果是1,則進行模2運算,即異或運算 crc ^= poly; crc <<= 1; } crc>>=1; while(r > 0){ code.set(code.size()-r, (crc&(1<<(r-1)))==0 ? 0 : 1); --r; } msg += ", CRC校驗碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); } public boolean crcCheck(ArrayList<Integer> code){ msg += ", 接收到信息碼: "; int poly = polynome[polynomeChoose];//選擇的多項式 int r = (int)(Math.log(poly)/Math.log(2) + 0.5)+1;//多項式的位數 int crc = 0;//余數 int highBit = 1<<r;//獲取crc的最高位 poly |= highBit; for(int i=0; i<code.size(); ++i){ msg += code.get(i); crc |= code.get(i); if((crc&highBit) != 0)//最高位如果是1,則進行模2運算,即異或運算 crc ^= poly; crc <<= 1; } crc>>=1; if(crc == 0){ msg += ", 校驗結果: 0, 正確!"; return true; } else{ msg += ", 校驗結果: " + Integer.toBinaryString(crc) + ", 出錯!"; return false; } } public static void main(String[] args) { int cd[]={1,0,1,1,0,0,1}; ArrayList<Integer> code = new ArrayList<Integer>(); for(int i=0; i<cd.length; ++i) code.add(cd[i]); new CrcCheck().toCrcCode(code); } }
奇偶校驗碼
奇偶校驗碼最簡單,但只能檢測出奇數位出錯. 如果發生偶數位錯誤就無法檢測. 但經研究是奇數位發生錯誤的概率大很多. 而且奇偶校驗碼無法檢測出哪位出錯.所以屬於無法矯正錯誤的校驗碼。奇偶校驗碼是奇校驗碼和偶校驗碼的統稱. 它們都是通過在要校驗的編碼上加一位校驗位組成. 如果是奇校驗加上校驗位后,編碼中1的個數為奇數個。如果是偶校驗加上校驗位后,編碼中1的個數為偶數個。
例:
原編碼 奇校驗 偶校驗
0000 0000 1 0000 0
0010 0010 0 0010 1
1100 1100 1 1100 0
1010 1010 1 1010 0
如果發生奇數個位傳輸出錯,那么編碼中1的個數就會發生變化. 從而校驗出錯誤,要求從新傳輸數據。目前應用的奇偶校驗碼有3種.
水平奇偶校驗碼對每一個數據的編碼添加校驗位,使信息位與校驗位處於同一行.
垂直奇偶校驗碼把數據分成若干組,一組數據排成一行,再加一行校驗碼. 針對每一行列采用奇校驗 或 偶校驗
例: 有32位數據10100101 00110110 11001100 10101011
垂直奇校驗 垂直偶校驗
10100101 10100101 數據
00110110 00110110
11001100 11001100
10101011 10101011
00001011 11110100 校驗
水平垂直奇偶校驗碼就是同時用水平校驗和垂直校驗
例:
奇校驗奇水平 偶校驗 偶水平
10100101 1 10100101 0 數據
00110110 1 00110110 0
11001100 1 11001100 0
10101011 0 10101011 1
00001011 0 11110100 1 校驗

package com.hjzgg.even_odd_check; import java.util.ArrayList; public class EvenOddCheck { private final boolean EVEN_CHECK = true; private final boolean ODD_CHECK = false; private boolean flag = ODD_CHECK; private String msg = null; public String getMsg(){ return msg; } public void setEvenCheck(){ flag = EVEN_CHECK; } public void setOddCheck(){ flag = ODD_CHECK; } public void toEvenOddCode(ArrayList<Integer> code){ msg = "信息源碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); int cnt1 = 0;//數字1的個數 for(int i=0; i<code.size(); ++i) if(code.get(i) == 1) ++cnt1; if(flag == EVEN_CHECK){ if((cnt1&1) == 1) code.add(0, 1); else code.add(0, 0); } else if(flag == ODD_CHECK){ if((cnt1&1) == 1) code.add(0, 0); else code.add(0, 1); } msg += ", 奇偶校驗碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); } public boolean evenOddCheck(ArrayList<Integer> code){ msg += ", 接收到信息碼: "; int cnt1 = 0;//數字1的個數 for(int i=0; i<code.size(); ++i){ msg += code.get(i); if(code.get(i) == 1) ++cnt1; } if((cnt1&1)==1 && flag == ODD_CHECK || (cnt1&1)==0 && flag==EVEN_CHECK){ msg += ", 校驗結果: 正確!"; return true; } else { msg += ", 校驗結果: 錯誤!"; return false; } } public static void main(String[] args) { } }
海明驗碼
海明碼也是利用奇偶性來校驗數據的. 它是一種多重奇偶校驗檢錯系統,它通過在數據位之間插入k個校驗位,來擴大碼距,從而實現檢錯和糾錯.
設原來數據有n位,要加入k位校驗碼.怎么確定k的大小呢? k個校驗位可以有pow(2,k) (代表2的k次方) 個編碼,其中有一個代表是否出錯. 剩下pow(2,k)-1個編碼則用來表示到底是哪一位出錯. 因為n個數據位和k個校驗位都可能出錯,所以k滿足pow(2,k)-1 >= n+k。
設 k個校驗碼為 P1,P2...Pk, n個數據位為D0,D1...Dn 產生的海明碼為 H1,H2...H(n+k) 。如有8個數據位,根據pow(2,k)-1 >= n+k可以知道k最小是4。那么得到的海明碼是:
H12 H11 H10 H9 H8 H7 H6 H5 H4 H3 H2 H1
D7 D6 D5 D4 P4 D3 D2 D1 P3 D0 P2 P1
然后怎么知道Pi校驗哪個位呢. 自己可以列個校驗關系表
海明碼 下標 校驗位組
H1(P1) 1 P1
H2(P2) 2 P2
H3(D0) 1+2 P1,P2
H4(P3) 4 P3
H5(D1) 1+4 P1,P2
H6(D2) 2+4 P2,P3
H7(D3) 1+2+4 P1,P2,P3
H8(P4) 8 P4
H9(D4) 1+8 P1,P4
H10(D5) 2+8 P2,P4
H11(D6) 1+2+8 P1,P2,P4
H12(D7) 4+8 P3,P4
從表中可以看出
P1校驗 P1,D0,D1,D3,D4,D6
P2校驗 P2,D0,D1,D2,D3,D5,D6
P3校驗 P3,D2,D3,D7
P4校驗 P4,D4,D5,D6,D7
其實上表很有規律很容易記,要知道海明碼Hi由哪些校驗組校驗,可以把i化成二進制數數中哪些位k是1,就有哪些Pk校驗
如H7 7=0111 所以由P1,P2,P3 H11 11=1011 所以由P1,P2,P4 H3 3=0011 所以由P1,P2
那看看Pi的值怎么確定,如果使用偶校驗,則
P1=D0 xor D1 xor D3 xor D4 xor D6
P2=D0 xor D1 xor D2 xor D3 xor D5 xor D6
P3=D1 xor D2 xor D3 xor D7
P4=D4 xor D5 xor D6 xor D7
其中xor是異或運算,奇校驗的話把偶校驗的值取反即可.那怎么校驗錯誤呢. 其實也很簡單. 先做下面運算.
G1 = P1 xor D0 xor D1 xor D3 xor D4 xor D6
G2 = P2 xor D0 xor D1 xor D2 xor D3 xor D5 xor D6
G3 = P3 xor D1 xor D2 xor D3 xor D7
G4 = P4 xor D4 xor D5 xor D6 xor D7

package com.hjzgg.hammingcheck; import java.util.ArrayList; import java.util.Collections; public class HammingCheck { private String msg = null; public String getMsg(){ return msg; } private int checkNumber_k(int n){ int kk = (int)(Math.log(n)/Math.log(2) + 0.5); for(int k=kk; ; ++k) if(n+k <= (int)(Math.pow(2.0, (double)k)+0.5)-1) return k; } public void toHammingCode(ArrayList<Integer> code){ msg = "信息源碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); Collections.reverse(code);//海明碼的編碼是從右到左,由小到大的 int n = code.size(); int k = checkNumber_k(n); int index = 1; for(int i=1; i<=k; ++i){//插入校驗位 code.add(index-1, 0); index<<=1; } //校驗位取值 for(int i=0; i<code.size(); ++i){ if(((i+1)&i) != 0){//如果這一位不是校驗位,也就是數據位 int x = i+1;//表示該有效數據是位於串中的幾位 int p_index = 1;//校驗位的索引 while(x != 0){ if((x&1) == 1) code.set(p_index-1, code.get(p_index-1)^code.get(i)); x>>=1; p_index<<=1;//下一個校驗位的索引 } } } Collections.reverse(code); msg += ", 海明校驗碼: "; for(int i=0; i<code.size(); ++i) msg += code.get(i); } public boolean hammingCheck(ArrayList<Integer> code){ msg += ", 接收到信息碼: "; Collections.reverse(code); ArrayList<Integer> s = new ArrayList<Integer>();//校驗的結果值 int k=1; while(k <= code.size()){//si的每一位初值為校驗位pi的值 s.add(code.get(k-1)); k<<=1; } for(int i=0; i<code.size(); ++i){ if(((i+1)&i) != 0){//如果這一位不是校驗位,也就是數據位 int x = i+1;//表示該有效數據是位於串中的第幾位 int p_index = 1;//校驗位的索引 while(x != 0){ if((x&1) == 1){ int s_index = (int)(Math.log(p_index)/Math.log(2.0) + 0.5)+1;//通過校驗位找到 對應的校驗結果s的索引 s.set(s_index-1, s.get(s_index-1)^code.get(i)); } x>>=1; p_index<<=1;//下一個校驗位的索引 } } } Collections.reverse(code); int ret = 0; int radix = 1; for(int i=0; i<s.size(); ++i){ ret += s.get(i)*radix; radix<<=1; } if(ret == 0){ msg += ", 校驗結果: 正確!"; return true; } else { Collections.reverse(s); msg += ", 校驗結果: " + s + ", 第" + ret + "位出錯!"; return false; } } public static void main(String[] args) { int cd[]={1,0,1,0}; ArrayList<Integer> code = new ArrayList<Integer>(); for(int i=0; i<cd.length; ++i) code.add(cd[i]); HammingCheck hc = new HammingCheck(); hc.toHammingCode(code); System.out.println("海明碼: " + code); //假設cdd中的是接受到的信息,然后利用海明碼糾錯檢驗 int cdd[]={1, 0, 1, 0, 0, 1, 1}; code.clear(); for(int i=0; i<cdd.length; ++i) code.add(cdd[i]); hc.hammingCheck(code); } }
執行程序部分:

package com.hjzgg.thread; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.Map; import java.util.TreeMap; import javax.swing.JOptionPane; import com.hjzgg.frame.MainFrame; public class MyThread implements Runnable{ private String xxxCode; private MainFrame mainFrame; private static final Map<String,Integer> mp = new TreeMap<String, Integer>(); static{ mp.put("HammingCode", 5210); mp.put("CrcCode", 5211); mp.put("EvenOddCode", 5212); } public MyThread(MainFrame mainFrame, String xxxCode){ this.mainFrame = mainFrame; this.xxxCode = xxxCode; } @Override public void run() { ServerSocket server=null; Socket socket=null; BufferedReader is = null; if(mp.get(xxxCode) == null) return; try{ server = new ServerSocket(mp.get(xxxCode)); while(true){ socket = server.accept(); is = new BufferedReader(new InputStreamReader(socket.getInputStream())); String codeText = is.readLine(); ArrayList<Integer> code = new ArrayList<Integer>(); for(int i=0; i<codeText.length(); ++i) code.add(Integer.parseInt(""+codeText.charAt(i))); if("HammingCode".equals(xxxCode)){ mainFrame.getHc().hammingCheck(code); JOptionPane.showMessageDialog(null, mainFrame.getHc().getMsg(), "海明校驗結果", JOptionPane.INFORMATION_MESSAGE); } else if("CrcCode".equals(xxxCode)){ mainFrame.getCc().crcCheck(code); JOptionPane.showMessageDialog(null, mainFrame.getCc().getMsg(), "CRC校驗結果", JOptionPane.INFORMATION_MESSAGE); } else { mainFrame.getEoc().evenOddCheck(code); JOptionPane.showMessageDialog(null, mainFrame.getEoc().getMsg(), "奇偶校驗結果", JOptionPane.INFORMATION_MESSAGE); } } } catch(Exception e){ System.out.println("Error:" + e.toString()); } finally { try{ if(is != null) is.close(); //關閉Socket輸入流 if(socket != null) socket.close(); //關閉Socket if(server != null) server.close(); //關閉ServerSocket } catch (Exception e){ System.out.println("Error:" + e.toString()); } } } }

package com.hjzgg.frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.PrintWriter; import java.net.Socket; import java.util.ArrayList; import java.util.Random; import com.hjzgg.crc.CrcCheck; import com.hjzgg.even_odd_check.EvenOddCheck; import com.hjzgg.hammingcheck.HammingCheck; public class MyActionListener implements ActionListener{ private MainFrame mainFrame; public MyActionListener(MainFrame mainFrame){ this.mainFrame = mainFrame; } private void myRandom(ArrayList<Integer> code){ Random random = new Random(); if(random.nextInt()%2 == 0){//出錯 int index = Math.abs(random.nextInt())%code.size(); code.set(index, code.get(index)^1); } } public void actionPerformed(ActionEvent e) { String codeText = mainFrame.getCodeText().getText(); ArrayList<Integer> code = new ArrayList<Integer>(); for(int i=0; i<codeText.length(); ++i) code.add(Integer.parseInt(""+codeText.charAt(i))); if(e.getActionCommand().equals("hammingBtn")){ try{ Socket socket=new Socket("127.0.0.1", 5210); PrintWriter os=new PrintWriter(socket.getOutputStream()); mainFrame.getHc().toHammingCode(code); myRandom(code); codeText = ""; for(int i=0; i<code.size(); ++i) codeText += code.get(i); os.print(codeText); os.flush(); socket.close(); //關閉Socket }catch(Exception ex) { System.out.println("Error:"+ex); //出錯,則打印出錯信息 } } else if(e.getActionCommand().equals("crcBtn")){ try{ Socket socket=new Socket("127.0.0.1", 5211); PrintWriter os=new PrintWriter(socket.getOutputStream()); mainFrame.getCc().toCrcCode(code); myRandom(code); codeText = ""; for(int i=0; i<code.size(); ++i) codeText += code.get(i); os.print(codeText); os.flush(); socket.close(); //關閉Socket }catch(Exception ex) { System.out.println("Error:"+ex); //出錯,則打印出錯信息 } } else { try{ Socket socket=new Socket("127.0.0.1", 5212); PrintWriter os=new PrintWriter(socket.getOutputStream()); mainFrame.getEoc().toEvenOddCode(code); myRandom(code); codeText = ""; for(int i=0; i<code.size(); ++i) codeText += code.get(i); os.print(codeText); os.flush(); socket.close(); //關閉Socket }catch(Exception ex) { System.out.println("Error:"+ex); //出錯,則打印出錯信息 } } } }
主程序:

package com.hjzgg.frame; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.HeadlessException; import java.awt.TextField; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JPanel; import com.hjzgg.crc.CrcCheck; import com.hjzgg.even_odd_check.EvenOddCheck; import com.hjzgg.hammingcheck.HammingCheck; import com.hjzgg.thread.MyThread; public class MainFrame extends JFrame{ private TextField codeText;//傳輸的信息碼 private HammingCheck hc = new HammingCheck(); private EvenOddCheck eoc = new EvenOddCheck(); private CrcCheck cc = new CrcCheck(); public HammingCheck getHc() { return hc; } public EvenOddCheck getEoc() { return eoc; } public CrcCheck getCc() { return cc; } public TextField getCodeText() { return codeText; } private JButton crcBtn = new JButton("CRC冗余校驗"); private JButton hammingBtn = new JButton("海明校驗"); private JButton evenOddBtn = new JButton("奇偶校驗"); private JComboBox evenOddComboBox=new JComboBox(); private JComboBox crcComboBox=new JComboBox(); private JComboBox hammingComboBox=new JComboBox(); private void init(){ JPanel topPanel = new JPanel(), downPanel = new JPanel(); topPanel.setPreferredSize(new Dimension(400, 80)); topPanel.setBackground(Color.blue); add(topPanel, BorderLayout.NORTH); downPanel.setPreferredSize(new Dimension(400, 180)); downPanel.setBackground(Color.green); add(downPanel, BorderLayout.SOUTH); FlowLayout topFlowLayout = new FlowLayout(); topFlowLayout.setAlignment(FlowLayout.CENTER); topFlowLayout.setVgap(20); topPanel.setLayout(topFlowLayout); JLabel label = new JLabel("信息碼:"); label.setForeground(Color.red); topPanel.add(label); codeText = new TextField(50); topPanel.add(codeText); FlowLayout downFlowLayout = new FlowLayout(); downFlowLayout.setHgap(10); downPanel.setLayout(downFlowLayout); JPanel evenOddPanel = new JPanel(), crcPanel = new JPanel(), hammingPanel = new JPanel(); evenOddPanel.setPreferredSize(new Dimension(90, 150)); crcPanel.setPreferredSize(new Dimension(350, 150)); hammingPanel.setPreferredSize(new Dimension(90, 150)); downPanel.add(evenOddPanel); downPanel.add(crcPanel); downPanel.add(hammingPanel); evenOddPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 30)); crcPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 30)); hammingPanel.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 30)); for(int i=0; i<CrcCheck.polynomeMsg.length; ++i) crcComboBox.addItem(CrcCheck.polynomeMsg[i]); evenOddComboBox.addItem("奇校驗"); evenOddComboBox.addItem("偶校驗"); hammingComboBox.addItem("好看而已"); crcPanel.add(crcComboBox); evenOddPanel.add(evenOddComboBox); hammingPanel.add(hammingComboBox); evenOddPanel.add(evenOddBtn); crcPanel.add(crcBtn); hammingPanel.add(hammingBtn); MyActionListener mcl = new MyActionListener(this); evenOddBtn.addActionListener(mcl); evenOddBtn.setActionCommand("evenOddBtn"); crcBtn.addActionListener(mcl); crcBtn.setActionCommand("crcBtn"); hammingBtn.addActionListener(mcl); hammingBtn.setActionCommand("hammingBtn"); setBounds(50, 100, 600, 300); setVisible(true); } public MainFrame() throws HeadlessException { super(); init(); } public MainFrame(String title) throws HeadlessException { super(title); init(); } public static void main(String[] args) { // TODO Auto-generated method stub MainFrame mainFrame = new MainFrame(); {//開啟服務端,准備接受信息碼 // "HammingCode" // "CrcCode" // "EvenOddCode" new Thread(new MyThread(mainFrame,"HammingCode")).start(); new Thread(new MyThread(mainFrame,"CrcCode")).start(); new Thread(new MyThread(mainFrame,"EvenOddCode")).start(); } } }
實驗結果: 有圖有真相!