3.1 資訊編碼
3.1.1 基本整型
TCP和UDP通訊端使我們能夠發送和接收位元組序列(數組),及範圍在0~255之間的整數。
下面考慮發送一個byte型整數、一個short型整數、一個int型整數和一個long型整數,這四個類型在Java中依次用1、2、4、8個位元組進行標示。
1. 發送順序,可以由低位到高位發送(little-endian),也可以由高位到低位發送(big-endian)。
考慮廠整型123456787654321L,其16禁止標示形式為0x0000704885F926B
1.如果使用little-endian順序傳輸這個整數,其位元組的十進位數值序列為:
如果使用big-endian順序傳輸這個整數,則其位元組的十進位數值序列為:
對於任何一個多位元組的整數,發送和接收方對於使用哪種傳輸順序必須達成一致。
2. 寄件者和接收者對於發送的數值是有符號的還是無符號的也要達成共識。Java中的四種基本整數類型都是有符號的。
下面的代碼中示範了發送和接收整數。
package com.suifeng.tcpip.chapter3;/** * 基本整型的發送和接收(類比) * * @author Administrator * */public class BruteForceCoding{// 要傳輸的參數private static final byte byteVal = 101;private static final short shortVale = 10001;private static final int intVal = 100000001;private static final long longVal = 1000000000001L;// 每種類型所佔的位元private static final int BSIZE = Byte.SIZE / Byte.SIZE;private static final int SSIZE = Short.SIZE / Byte.SIZE;private static final int ISIZE = Integer.SIZE / Byte.SIZE;private static final int LSIZE = Long.SIZE / Byte.SIZE;// 淹沒private final static int BYTEMASK = 0xff;/** * 將要傳輸的位元據列印出來 * * @param bArray * 位元組 * @return */public static String byteArray2DecimalString(byte[] bArray){StringBuilder rbtn = new StringBuilder(256);for (byte b : bArray){rbtn.append(b & BYTEMASK).append(" ");}return rbtn.toString();}/** * 將要發送的整數轉換成位元組 * * @param dst * 目的位元組 * @param val * 要傳輸的整數 * @param offset * 位移 * @param size * 所佔位元組數 * @return */public static int encodeIntBigEndian(byte[] dst, long val, int offset,int size){for (int i = 0; i < size; i++){dst[offset++] = (byte) (val >> (size - i - 1) * Byte.SIZE);}return offset;}/** * 解析編碼後的資料 * * @param val * 加密後的位元組 * @param offset * 位移 * @param size * 大小 * @return */public static long decodeIntBigEndian(byte[] val, int offset, int size){long rbtn = 0;for (int i = 0; i < size; i++){rbtn = (rbtn << Byte.SIZE) | ((long) val[offset + i] & BYTEMASK);}return rbtn;}public static void main(String[] args){byte[] message = new byte[BSIZE + SSIZE + ISIZE + LSIZE];// byte類型int offset = encodeIntBigEndian(message, byteVal, 0, BSIZE);// short類型offset = encodeIntBigEndian(message, shortVale, offset, SSIZE);// int類型offset = encodeIntBigEndian(message, intVal, offset, ISIZE);// long類型offset = encodeIntBigEndian(message, longVal, offset, LSIZE);System.out.println("Encode message:" + byteArray2DecimalString(message));// 解析加密後的資料offset = 0;// 解析bytelong value = decodeIntBigEndian(message, offset, BSIZE);System.out.println("Byte Value=" + value);// 解析shortoffset += BSIZE;value = decodeIntBigEndian(message, offset, SSIZE);System.out.println("Short Value=" + value);// 解析intoffset += SSIZE;value = decodeIntBigEndian(message, offset, ISIZE);System.out.println("Int value=" + value);// 解析longoffset += ISIZE;value = decodeIntBigEndian(message, offset, LSIZE);System.out.println("Long value=" + value);}}
執行結果如下
如所示,運行過程中產生了一個位元組序列
還有一一種方式可以使用Java提供的二進位的讀寫操作。
package com.suifeng.tcpip.chapter3;import java.io.ByteArrayInputStream;import java.io.ByteArrayOutputStream;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;/** * 基本整型的發送和接收(類比) * * @author Administrator * */public class BruteForceCoding2{// 要傳輸的參數private static final byte byteVal = 101;private static final short shortVal = 10001;private static final int intVal = 100000001;private static final long longVal = 1000000000001L;public static void main(String[] args){byte[] msg = null;ByteArrayOutputStream buf = new ByteArrayOutputStream();DataOutputStream out = new DataOutputStream(buf);System.out.println("要發送的資料:");System.out.println("Byte Value="+byteVal);System.out.println("Short Value="+shortVal);System.out.println("Int Value="+intVal);System.out.println("Long Value="+longVal);try{out.writeByte(byteVal);out.writeShort(shortVal);out.writeInt(intVal);out.writeLong(longVal);out.flush();msg = buf.toByteArray();}catch (IOException e){// TODO Auto-generated catch blocke.printStackTrace();}finally{try{if(buf != null){buf.close();}if(out != null){buf.close();}}catch (IOException e){// TODO Auto-generated catch blocke.printStackTrace();}}System.out.println();ByteArrayInputStream bais = new ByteArrayInputStream(msg);DataInputStream dis = new DataInputStream(bais);try{System.out.println("接收到的資料:");System.out.println("Byte Value="+dis.readByte());System.out.println("Short Value="+dis.readShort());System.out.println("Int Value="+dis.readInt());System.out.println("Long Value="+dis.readLong());}catch (IOException e){// TODO Auto-generated catch blocke.printStackTrace();}}}
執行結果如下
3.1.2 字串和文本
調用String的getByte方法可以返回一個根據平台預設字元集對String執行個體進行編碼的字元數組。要保證一個字串按照特定的字元集編碼,只需要將字元集的名字傳遞給getBytes方法,其返回的自己數組就包含了指定字元集的字串。
寄件者和接收者必須在表示字串的方式上達成共識。
3.1.3 位操作:布爾值編碼
位元影像(bitmap)是對布爾資訊進行編碼的一種非常緊湊的方式,位元影像的主要思想是根據位元影像中的每一位都能夠表示一個布爾值編碼,通常是0表示false,1表示true。要操縱位元影像,可以考慮使用掩碼,其中一位或者多位設為1,其他各位被清空。
下面是針對位元影像進行的操作
package com.suifeng.tcpip.chapter3;/** * 位元影像和掩碼的操作 * @author Suifeng * */public class BitmapTest{private final static int BIT2 = (1 << 2);// 0000 0100private final static int BIT3 = (1 << 3);// 0000 1000private final static int BIT5 = (1 << 5);// 0010 0000private final static int BIT7 = 0x80;// 0100 0000private final static int BIT2_AND_BIT3 = 12;// 0000 0110public static void main(String[] args){int bitmap = 1234567;System.out.println("將bitmap中的第五位置為1");// 將bitmap中第五位置為1bitmap |= BIT5;System.out.println("第五位是否為1:"+(((bitmap & BIT5) & BIT5) != 0));System.out.println();System.out.println("將bitmap中的第七位置為0");// 將bitmap中第七位置為1 取BIT7的補碼,然後與原值按位與bitmap &= ~BIT7;System.out.println("第七位是否為1:"+(((bitmap & BIT7) & BIT7) == 0));System.out.println();System.out.println("將bitmap中的第二、三、五位置為0");// 將bitmap第2、3、5位置為0bitmap &= ~(bitmap & (BIT2_AND_BIT3 | BIT5));System.out.println("第二位是否為0:"+(((bitmap & BIT2) & BIT2) == 0));System.out.println("第三位是否為0:"+(((bitmap & BIT3) & BIT3) == 0));System.out.println("第五位是否為0:"+(((bitmap & BIT5) & BIT5) == 0));}}
執行結果如下