摘要:閑談系列不涉及具體的講解,只會(huì)勾勾畫畫一些自己認(rèn)為比較重要的特性。我們一般認(rèn)為用兩個(gè)字節(jié)位表示,并且完全囊括了字符集。將其轉(zhuǎn)換成進(jìn)制就是只是表示它們是碼。三的讀取和寫入相關(guān)重要的只有能夠讀寫,才能夠顯示其存在的價(jià)值。
原文地址:http://www.cnblogs.com/DeanCh...
在剛接觸Nodejs的時(shí)候,有些概念總讓學(xué)前端的我感到困惑(雖然大學(xué)的時(shí)候也是在搞后端,世界上最好的語(yǔ)言,you know)。我可以很快理解File System,Path等帶有明顯功能的模塊,卻一下子不能理解Buffer這個(gè)玄而又玄的東西。因?yàn)椋谇岸说膉s實(shí)踐中,我很少去考慮什么編碼方式,字符集之類的東西。二進(jìn)制的理解僅限于大學(xué)課堂而已。本文與其說(shuō)是在探討Node的Buffer模塊,倒不如說(shuō)是來(lái)探討下如何從字符集,編碼的角度來(lái)理解Buffer這個(gè)模塊設(shè)立的意義。Node閑談系列不涉及具體的API講解,只會(huì)勾勾畫畫一些自己認(rèn)為比較重要的特性。
一、基本知識(shí)正如我們學(xué)習(xí)編程的第一節(jié)課一樣,我們明白,計(jì)算機(jī)就是一個(gè)二進(jìn)制生物。它只能理解1和0,或者說(shuō)有和沒有?!疤珮O生兩儀,兩儀生四象,四象生八卦”。我們?cè)谟?jì)算上看到的無(wú)論是任何東西,都是通過(guò)某種特殊的編碼方式,或者說(shuō)是約定展現(xiàn)出來(lái)的。
我們很熟悉的ASCII碼就是這樣一種規(guī)范,和摩爾斯碼一樣,固定的值表示固定的含義。ASCII碼用1個(gè)字節(jié)8位來(lái)表示2^8=256種狀態(tài)。比如大寫字母A對(duì)應(yīng)的是65,B對(duì)應(yīng)66,是不是很簡(jiǎn)單。ASCII碼并不是占滿了所有的256個(gè)位置,只用到了一半128位。在一個(gè)字節(jié)中,只占用后面7位,最前面一位統(tǒng)一標(biāo)識(shí)為0。
但是我們很容易就發(fā)現(xiàn),ASCII碼遠(yuǎn)遠(yuǎn)是不夠的,最起碼我們漢字就表示不了。后面考慮了許多其他解決方案,我們?cè)诖瞬欢鄶⑹?,直接說(shuō)最終解決方案——Unicode。Unicode想法很直接,就是想把全世界所有的字符都囊括進(jìn)去。我們一般認(rèn)為Unicode用兩個(gè)字節(jié)16位表示,并且完全囊括了ASCII字符集。比如漢字“好”在unicode里面二進(jìn)制表示是 0101 1001 0111 1101。將其轉(zhuǎn)換成16進(jìn)制就是U597D(U只是表示它們是unicode碼)。之所以我前面說(shuō)是“一般認(rèn)為”,是因?yàn)檫@種想法是不準(zhǔn)確的。Unicode一個(gè)平面(plane)是兩個(gè)字節(jié)。我們經(jīng)常談?wù)摰氖撬囊粋€(gè)基本平面,編碼是U+0000到U+FFFF,常見字符都在這個(gè)平面。Unicode還有16個(gè)輔助平面,碼點(diǎn)范圍是U+010000一直到U+10FFFF。一般而言,我們只需要把關(guān)注點(diǎn)放在基本平面就好,并且要習(xí)慣Unicode的表示方式。因?yàn)?,這是畢竟在各種編碼方式間轉(zhuǎn)化的“硬通貨”。
我們常常談到的utf-8,utf-16這些是什么呢?這些都是具體的編碼方式,而Unicode是個(gè)字符集。以u(píng)tf-8為例,它在unicode碼的基礎(chǔ)上,進(jìn)行重新編碼,把一些本身不需要占滿2個(gè)字節(jié)的轉(zhuǎn)化為1個(gè)字節(jié)。比如ASCII里面的那些字符,在unicode里面,第一個(gè)字節(jié)全是0,簡(jiǎn)直是空間的浪費(fèi),也會(huì)把漢字編碼城3個(gè)字節(jié)。你盡可以在控制臺(tái)試下Buffer.from("我","utf8")看下編碼后占的字節(jié)數(shù)。
javascript使用哪種編碼方式?
javascript采用Unicode字符集,但是只支持一種編碼方式。那就是USC-2。是不是沒有聽說(shuō)過(guò)?你可以把它理解成utf-16。但它和utf-16到底是什么關(guān)系呢?
兩者的關(guān)系簡(jiǎn)單說(shuō),就是UTF-16取代了UCS-2,或者說(shuō)UCS-2整合進(jìn)了UTF-16。所以,現(xiàn)在只有UTF-16,沒有UCS-2。
UCS-2只支持兩個(gè)字節(jié),而在它后面才出來(lái)的UTF-16在UCS-2的基礎(chǔ)上,利用輔助平面可以支持4個(gè)字節(jié)。既然是UCS-2整合進(jìn)UTF-16,那就存在有的字符UTF-16有,而UCS-2不存在的情況。出現(xiàn)這種情況怎么辦?大家可以參考下參考資料里面阮老師的講述。
二、Buffer的生成相關(guān)重要的API
Buffer.alloc(size[, fill[, encoding]])
Buffer.allocUnsafe(size)
Buffer.allocUnsafeSlow(size)
Buffer.from(array)
buf.fill(value[, offset[, end]][, encoding])
在Buffer生成的過(guò)程中,最大的關(guān)注點(diǎn)就是內(nèi)存的申請(qǐng)和分配。原先new Buffer()生成Buffer的方法已經(jīng)不建議再次使用,它和Buffer.allocUnsafe()方法一樣,可能包含敏感數(shù)據(jù)。
為什么會(huì)包含敏感數(shù)據(jù)呢?在生成buffer的過(guò)程中,不是一步到位,要分為兩步走,1,申請(qǐng)內(nèi)存空間,2,申請(qǐng)的內(nèi)存空間進(jìn)行填充。Buffer.allocUnsafe()方法只完成了第一步。不完成第二步的后果就是,申請(qǐng)的空間可能“殘留了”以前內(nèi)存上的數(shù)據(jù)。畢竟一塊兒內(nèi)存在計(jì)算機(jī)中總是申請(qǐng)了再釋放,釋放了再申請(qǐng),難免就會(huì)導(dǎo)致一些數(shù)據(jù)沒有被及時(shí)清理干凈。當(dāng)然,由于少了第二步操作,速度自然快了不少。
const a = Buffer.allocUnsafe(10); console.log(a) //打印結(jié)果總是不一樣的,但我們發(fā)現(xiàn)每一位上很可能不是00,這些數(shù)據(jù)就屬于敏感數(shù)據(jù)。
可以使用buf.fill(0)進(jìn)行后期的填充。但為了避免漏洞產(chǎn)生,應(yīng)該避免使用Buffer.allocUnsafe()來(lái)分配內(nèi)存。
Buffer.alloc()比Buffer.allocUnsafe()安全的原因在于它在第二步會(huì)把所有的舊數(shù)據(jù)清除掉,填充成0。
const a = Buffer.alloc(10); console.log(a) //打印結(jié)果每一位都是0。
看到這里,你是不是以為Buffer.alloc()和Buffer.allocUnsafe()的區(qū)別僅限于有沒有填充數(shù)據(jù)?其實(shí)并不是的。真正與Buffer.alloc()差別在是否填充數(shù)據(jù)的是Buffer.allocUnsafeSlow()。原來(lái),使用Buffer.allocUnsafe()分配內(nèi)存需要借助共享內(nèi)存池(shared internal memory pool)。而Buffer.alloc()和Buffer.allocUnsafeSlow()是直接在內(nèi)存空間上開辟相應(yīng)大小的內(nèi)存空間。
Buffer.allocUnsafe() (與之前的 new Buffer(size) 機(jī)制類似)是三者中分配內(nèi)存速度最快的方式,它采用了共享內(nèi)存池(shared internal memory pool)這一方式,通過(guò)預(yù)先分配一定大小的一段內(nèi)存,從中再向 JavaScript 分配相應(yīng)大小的片段,避免頻繁的向系統(tǒng)申請(qǐng)內(nèi)存分配,來(lái)達(dá)到較高的效率。共享內(nèi)存池的默認(rèn)值 poolSize 為 8KB(可重新賦值),只有當(dāng)需要分配的內(nèi)存小于等于 poolSize 的一半時(shí),Buffer.allocUnsafe() 才會(huì)從共享內(nèi)存池從分配空間。
這里的知識(shí)點(diǎn)到為止,詳細(xì)的探討以后可以可以考慮專門寫一篇來(lái)說(shuō)明,參考資料的內(nèi)容也是相當(dāng)不錯(cuò),建議閱讀。
三、Buffer的讀取和寫入相關(guān)重要的API
buf.readInt8(offset[, noAssert])
buf.readDoubleBE(offset[, noAssert])
buf.readDoubleLE(offset[, noAssert])
buf.writeUInt8(value, offset[, noAssert])
buf.writeUInt16BE(value, offset[, noAssert])
buf.writeUInt16LE(value, offset[, noAssert])
...
buffer只有能夠讀寫,才能夠顯示其存在的價(jià)值。查看Buffer的文檔,Buffer的讀寫方法中有非常多以“BE”和“LE”結(jié)尾的方法。他們分別代表什么呢?
大字序和小字序
“BE”表示的是“big endian”大端字節(jié)序,而“LE”自然表示“l(fā)ittle endian”小端字節(jié)序。字節(jié)序是干什么的呢?我們?cè)诿枋鲆粋€(gè)字符的unicode碼的時(shí)候,習(xí)慣性地從左到右去寫。為什么不可以從右右往左寫呢?多個(gè)字節(jié)無(wú)論是讀取還是寫入,總要有一個(gè)順序,這就是“字節(jié)序”。大端序就是我們??吹降母呶蛔止?jié)在前,低位字節(jié)在后,小端序恰好相反。
為什么要區(qū)分大端序和小端序呢?不能都統(tǒng)一從一個(gè)方向讀取,寫入么?
計(jì)算機(jī)電路先處理低位字節(jié),效率比較高,因?yàn)橛?jì)算都是從低位開始的。所以,計(jì)算機(jī)的內(nèi)部處理都是小端字節(jié)序。
但是,人類還是習(xí)慣讀寫大端字節(jié)序。所以,除了計(jì)算機(jī)的內(nèi)部處理,其他的場(chǎng)合幾乎都是大端字節(jié)序,比如網(wǎng)絡(luò)傳輸和文件儲(chǔ)存。字節(jié)序的處理,就是一句話:"只有讀取的時(shí)候,才必須區(qū)分字節(jié)序,其他情況都不用考慮。"
好,下面我們舉個(gè)實(shí)際的例子。
var buf = Buffer.from([1,3,5,7]); //buf.readInt16BE(0) //259 從buf中讀取16位的整數(shù),所以讀取的第一個(gè)字符對(duì)應(yīng)的碼點(diǎn)是 01 03轉(zhuǎn)化成10進(jìn)制就是1*16^2+3 = 259。 buf.readInt16LE(0) //756 // 小字序從右往左讀取,第一個(gè)字符對(duì)應(yīng)的碼點(diǎn)是 03 01 轉(zhuǎn)化成10進(jìn)制就是3*16^2+1 = 756
讀取和寫入是一個(gè)相反的過(guò)程,道理是一樣的。
//官方示例 const buf = Buffer.allocUnsafe(4); buf.writeUInt8(0x3, 0); buf.writeUInt8(0x4, 1); buf.writeUInt8(0x23, 2); buf.writeUInt8(0x42, 3); // Prints:console.log(buf);
Buffer還有很多很有意思的方面需要進(jìn)一步學(xué)習(xí),待以后再進(jìn)一步補(bǔ)充本文或者寫幾篇相關(guān)更為深入的文章。
未完待續(xù)。。。
參考資料Unicode與JavaScript詳解
字符編碼筆記:ASCII,Unicode 和 UTF-8
Node.js 模塊之 Buffer
Node源碼解析 – buffer
理解字節(jié)序
Buffer/Stream與內(nèi)存管理
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/89576.html
摘要:而的主線程中不允許操作網(wǎng)絡(luò),更是將程序員們推向了異步的深淵。異步深淵產(chǎn)生的主要原因是回調(diào),這在里尤其嚴(yán)重。為了逃離回調(diào)的深淵,大家開始想各種辦法來(lái)把回調(diào)扁平化。目前已經(jīng)在等環(huán)境中得到支持,使用的不僅能大大簡(jiǎn)化代碼,還能降低邏輯思路的復(fù)雜度。 哦,代碼……就把它們當(dāng)成插圖吧 隨著 CPU 從單核變多核,軟件從注重功能到注重體驗(yàn),Web 從頁(yè)面跳轉(zhuǎn)方式到 Web2.0 的無(wú)刷新加載(AJA...
摘要:新晉技術(shù)專家下面是墨天輪部分新晉的技術(shù)專家。大家可以點(diǎn)擊往期閱讀墨天輪技術(shù)專家邀請(qǐng)函了解詳情,申請(qǐng)成為我們的技術(shù)專家,加入專家團(tuán)隊(duì),與我們一起創(chuàng)建一個(gè)開放互助的數(shù)據(jù)庫(kù)技術(shù)社區(qū)。新關(guān)聯(lián)公眾號(hào)墨天輪是一個(gè)開放互助的數(shù)據(jù)庫(kù)技術(shù)社區(qū)。 引言 近期我們?cè)贒BASK小程序增加了數(shù)據(jù)庫(kù) MongoDB、Redis、 Elasticsearch、DB2、Weblogic 等新的的專題欄目和一些新的技術(shù)...
摘要:主要介紹的主要特性和一些經(jīng)驗(yàn)。先從整體上看一下的一些理念和基本架構(gòu),然后從網(wǎng)絡(luò)資源管理存儲(chǔ)服務(wù)發(fā)現(xiàn)負(fù)載均衡高可用安全監(jiān)控等方面向大家簡(jiǎn)單介紹的這些主要特性。集群范圍內(nèi)的監(jiān)控主要由和如構(gòu)建。 主要介紹 Kubernetes 的主要特性和一些經(jīng)驗(yàn)。先從整體上看一下Kubernetes的一些理念和基本架構(gòu), 然后從網(wǎng)絡(luò)、 資源管理、存儲(chǔ)、服務(wù)發(fā)現(xiàn)、負(fù)載均衡、高可用、rolling upgra...
閱讀 2836·2021-11-19 11:35
閱讀 2588·2021-11-02 14:40
閱讀 1409·2021-09-04 16:48
閱讀 3015·2019-08-30 15:55
閱讀 1769·2019-08-30 13:11
閱讀 1963·2019-08-29 11:12
閱讀 1097·2019-08-27 10:52
閱讀 3168·2019-08-26 18:36