網路傳輸中二進位數據怎麼還原為位元組?

在網路中傳輸數據時,最後都是會轉化成二進位或者十六進位流,但是還原的時候怎麼辦,比如英文是單位元組的,漢字是雙位元組的,系統怎麼識別應該按照單位元組還是雙位元組去還原二進位流??


英文詩單位元組的,漢字是雙位元組

先吐槽這句。沒有具體編碼,誰說漢字一定是雙位元組的。最廣泛應用的UTF8編碼里漢字可能是3位元組甚至4位元組。如果用了UTF-16,大部分字元包括英文都是2位元組的。

多位元組編碼是經過仔細設計的,拿到一個位元組,就能知道它應該和以後的幾個位元組組成一個碼點,長度不同的編碼沒有共同前綴,不會造成歧義。拿UTF8這種變長編碼為例:

單位元組:必以0開頭,(0XXX XXXX),和ASCII一致。

雙位元組:第一個位元組以110開頭 (110X XXXX)+(10XX XXXX)

三位元組:第一個位元組以1110開頭 (1110 XXXX)+(10XX XXXX)+(10XX XXXX)

四位元組、五位元組等等的情況前綴就是幾個1加一個0.

所以看第一個位元組的前幾位就知道應該再讀幾個位元組去解碼一個字元了。


將文本、音樂、視頻等轉換為二進位流的過程,可以看作是一種「加密」,而將這個過程反轉,從二進位流轉換為有實際意義的數據的過程則為「解密」。

而加密方法就是我們常說的編碼格式。將二進位流轉換為原始數據,知道編碼格式是必須的。得知的方法有:

    1. 二進位流中本身就留有特徵碼(如:點陣圖文件格式開頭的簽名,BM 之類的 ASCII 碼。)
    2. 根據統計學原理,從二進位數據本身的特徵上猜測編碼(如:嘗試對文本文件按照從嚴到松的順序應用字元編碼,認為第一個可以完全解碼的字元編碼為該文本文件的編碼。
    3. 其它相關信息(如:從擴展名猜測文件的格式)
  1. 額外的協議約定,這個是網路傳輸中最常見的。即在數據流里插入編碼相關信息(如:在二進位數據前加一個位元組,表示應該用什麼方式解碼)。


不懂Java,也不懂網路傳輸。這裡就談一下字元編碼的問題。

題主的題乾和描述實際上是兩個不同的問題。

首先是二進位和位元組的問題。
一個位元組是8位。對於16位二進位:

1110101110100100

前面的11101011是1個位元組,後面的10100100又是1個位元組,2個位元組,直接分組即可。
但二進位顯得冗長單調,因此在實際應用中,十六進位更受青睞。
上面的例子用十六進位表示是EBA4,這意味著兩位十六進位數表示一個位元組。
在http://VB.net和C#中,二進位是以Byte數組的形式存儲的,因為1個Byte正好可以表示1個位元組。(位元組的英文就是Byte。)
那麼二進位和位元組不存在所謂的「還原」或著「轉換」問題,它們是一個東西。或者說位元組可以用二進位來表示,二進位以位元組的形式存儲。

不過注意到還可以用BitArray存儲二進位,如何實現從BitArray到Byte數組的互轉?

BitArray到Byte數組:
VB

Function BitArray2Bytes(bits As BitArray) As Byte()
If Not bits.Count Mod 8 = 0 Then Throw New ArgumentException("無法轉換為Byte數組")
Dim bytes(bits.Count / 8 - 1) As Byte
bits.CopyTo(bytes, 0)
Return bytes
End Function

C#

byte[] ConvertToByte(BitArray bits)
{
if (bits.Count % 8 != 0)
{
throw new ArgumentException("無法轉換為Byte數組");
}
byte[] bytes = new byte[bits.Count / 8-1];
bits.CopyTo(bytes, 0);
return bytes;
}

Byte數組到BitArray:

直接構造一個即可。

VB

Dim bits As New BitArray{bytes()}

C#

BitArray bits= new BitArray(bytes[]);

當然從描述看,題主的本意是如何從二進位中獲取字元

首先,你要確定傳過來的二進位是表示文本,才有繼續討論的必要。

接著,確定其編碼方式,是ANSI,是UTF-8,還是其他?這對正確顯示文本是很重要的。

在.net里,System.Text命名空間中有將文本和二進位流互轉的方法,具體是:

System.Text.Encoding.UTF8.GetString()
System.Text.Encoding.UTF8.GetBytes()

當然不一定是UTF-8,還有其他編碼可供選擇,如UTF-7、Unicode(實際上是UTF-16 LE)、UTF-32 LE、ASCII。另外,還有一個默認的是操作系統當前 ANSI 代碼頁的編碼。

詳見Encoding 類 (System.Text)。

還有題主的描述有問題,在UTF-8編碼里,漢字(或者Unicode的名稱叫CJK,中日韓統一表意文字),並不一定是用兩個位元組來存儲擴展B區以後的那6萬漢字已經怒不可遏了,存儲它們需要4個位元組。這些字通常罕用,一般用在方言、古籍、文字學領域,不過也有一些類推簡化字是通用的,甚至有些用在人名中——這些人正為打不出自己的名字而感到困擾。


補充一下,如果這個問題是關於字元編碼,字元編碼主要分為以下三類:

ASCII:最早的編碼,只支持英文,每個字元佔一個位元組且最高位為0。

ANSI編碼:注意ANSI編碼不是指一種編碼,而是各個國家為了支持自己語言自己制定的編碼標準,如中文環境下ANSI編碼就是指GB2312編碼。ANSI編碼最高位為0時為ASCII編碼,一個字元依舊一個位元組,最高位為1時是拓展編碼,一個字元兩個位元組。

不同ANSI編碼之間相互不兼容。

Unicode編碼:又稱萬國碼,將各個國家的字元進行了統一編址。

注意Unicode只是一種編碼方式,其實現有UTF-8(變長),UTF-16(定長)等。

此外:

Windows系統使用ANSI編碼,Linux系統使用UTF-8編碼,所以如果用OpenSSH從Windows連接Linux會顯示亂碼。

網頁開發常用UTF-8和GBK(GB2312的擴展),通常國際化的站點會用UTF-8,只面向中文用戶的站點用GB2312或GBK。如國內新浪使用GB2312,北美新浪使用UTF-8。


推薦閱讀:

MacBook Pro適合編程嗎?
JSON「最後不能加逗號」是不是錯誤設計?
我知道英語很重要,也很想學英語,但總是很懶,不想背單詞怎麼辦?
為什麼大多數編程語言只有異或運算符而沒有同或運算符?
c++11 condition_variable的問題?

TAG:編程 | 計算機 | Unicode統一碼 | Java | 計算機網路 |