日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Node.js模块之Buffer

發布時間:2024/4/13 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Node.js模块之Buffer 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

簡言

在沒有出現Node.js之前,JavaScript還是運行在瀏覽器端,對于處理Unicode編碼的字符串數據很容易,但是對于處理二進制以及非Unicode編碼的數據無能為力,但是對于Server端操作TCP以及文件I/O的處理是必須的。在Node.js里面提供了Buffer類處理二進制的數據,可以處理各種類型的數據。并且在Node.js里面一些重要模塊net、http、fs中的數據傳輸以及處理都有Buffer的身影,因為一些基礎的核心模塊都要依賴Buffer,所以在node啟動的時候,就已經加載了Buffer,我們可以在全局下面直接使用Buffer。


創建Buffer對象:new Buffer不安全?

在v6.0之前創建Buffer對象直接使用new Buffer()構造函數來創建對象實例,但是Buffer對內存的權限操作相比很大,可以直接捕獲一些敏感信息,所以在v6.0以后,官方文檔里面建議使用Buffer.from()接口去創建Buffer對象。直接對比buffer.js的源碼,看看兩者有什么區別

// Buffer構造函數的源碼 function Buffer(arg, encodingOrOffset, length) {if (typeof arg === 'number') {if (typeof encodingOrOffset === 'string') {throw new Error('If encoding is specified then the first argument must be a string');}return Buffer.allocUnsafe(arg);}return Buffer.from(arg, encodingOrOffset, length); } // Buffer.from函數的源碼 Buffer.from = function(value, encodingOrOffset, length) {if (typeof value === 'number')throw new TypeError('"value" argument must not be a number');if (isArrayBuffer(value) || isSharedArrayBuffer(value))return fromArrayBuffer(value, encodingOrOffset, length);if (typeof value === 'string')return fromString(value, encodingOrOffset);return fromObject(value); };

由源碼里面可以看到Buffer構造函數里面會判斷第一個參數是否為數字類型而調用allocUnsafe接口或者是直接調用from接口去創建實例,而這兩種創建對象的唯一區別就在于Buffer構造函數方式的第一個參數是數字類型,那么就是說,如果我們使用構造函數方式創建時候第一個參數不傳數字類型就和from接口創建的邏輯是一致的,相對會更加安全。接下來看為啥如果第一個參數傳遞是數字的話會可能存在安全風險,如果第一個參數是數字,Buffer構造函數會去分配一個內存空間給到實例化的buffer使用,而調用allocUnsafe接口去分類內存的時候,分配出來的內容空間是沒有被初始化(數據沒被重置),很有可能會攜帶該緩存區之前的數據,如果緩存里面的內容是一些私鑰、密碼等敏感信息的話就可有可能被泄漏出去,下面舉個例子:

var password = 'thisIsMyPassword'; for( var i = 0, i < 100000; i++ ) {var buf = (new Buffer(200)).toString('ascii');if (buf.indexOf(token) !== -1) {console.log('Found at i ' + i + ': ' + buf);} } // password內存申請的存儲可能在new Buffer里面泄漏出去

而最初new Buffer()API這樣設計的會使得內存的分配非常快,因為不用每次都不用去初始化重置分配到的內容空間,雖然有一定的性能優勢,但是也有一定的安全風險,下面是具體的性能耗時對比:

console.time('new'); for( var i = 0;i< 1000000;i++) {new Buffer(2000); } console.timeEnd('new');console.time('alloc'); for( var i = 0;i< 1000000;i++) {Buffer.alloc(2000); } console.timeEnd('alloc');// 運行結果,不初始化比初始化更快 // new: 1498ms // alloc: 2439ms

v6.0之后的版本都建議使用Buffer.alloc()接口去分配內存,以及使用Buffer.from()接口去創建Buffer實例,與此同時,新版也維持Buffer.allocUnsafe()接口,但是語義上面已經說的明確,此外,在開啟安全方面,我們業務–zero-fill-buffers來默認啟用內存初始化,最后以下是總結:

  • 使用new Buffer()構造函數創建Buffer對象實例并非絕對的不安全

  • alloc接口分配內存空間會初始化內存,不會泄漏舊緩存

  • allocUnsafe接口分配內存空間速度更優,但有數據安全風險


內存分配

Buffer可直接操作二進制數據類型,這必然要有二進制數據的載體,而在JavaScript里面已經實現了ArrayBuffer對象、TypedArray對象以及DataView對象在ES6的時候納入了ECMAScript規格里面。其實這些數據結構也被應用在瀏覽器端,例如File API、WebGL、Canvas、WebSockets等一些API底層都是二進制數據的通信,查看node_buffer.cc源碼,Buffer在C++層面分配內存最終也是使用ArrayBuffer對象作為載體,現在先區分一下ArrayBuffer、TypedArray以及DataView三者的區別。

  • ArrayBuffer對象 : 內存中一段原始的二進制數據,可以通過“視圖”進行操作。

  • TypedArray對象 : 用來生成內存的視圖,通過9個構造函數,可以生成9種數據格式的視圖,比如Buffer里面就使用到Uint8Array(無符號8位整形)數組視圖。

  • DataView對象 : 暫時與本文無關不做詳細介紹。

簡單點而言, 就是Buffer模塊使用v8::ArrayBuffer分配一片內存,通過TypedArray中的v8::Uint8Array來去寫數據 ,而說道Buffer的內存分配就不得不說Buffer的8KB的問題,對應buffer.js源碼里面的處理就是

Buffer.poolSize = 8 * 1024;function allocate(size) {if(size <= 0 )return new FastBuffer();if(size < Buffer.poolSize >>> 1 )if(size > poolSize - poolOffset)createPool();var b = allocPool.slice(poolOffset,poolOffset + size);poolOffset += size;alignPool();return b} else {return createUnsafeBuffer(size);} }

源碼直接看來就是以8KB作為界限,如果寫入的數據大于8KB一半的話直接則直接去分配內存,如果小于4KB的話則從當前分配池里面判斷是否夠空間放下當前存儲的數據,如果不夠則重新去申請8KB的內存空間,把數據存儲到新申請的空間里面,如果足夠寫入則直接寫入數據到內存空間里面,下圖為其內存分配策略。

如上圖,如果當前存儲了2KB的數據,后面要存儲5KB大小數據的時候分配池判斷所需內存空間大于4KB,則會去重新申請內存空間來存儲5KB數據并且分配池的當前偏移指針也是指向新申請的內存空間,這時候就之前剩余的6KB(8KB-2KB)內存空間就會被擱置。至于為什么會用8KB作為存儲單元分配,這里還沒進一步深究。

此外,Buffer單次的內存分配也有限制,而這個限制根據不同操作系統而不同,而這個限制可以看到node_buffer.h里面

static const unsigned int kMaxLength =sizeof(int32_t) == sizeof(intptr_t) ? 0x3fffffff : 0x7fffffff;

對于32位的操作系統單次可最大分配的內存為1G,對于64位或者更高的為2G


Buffer與String

Buffer與String兩者都可以存儲字符串類型的數據,但是,String與Buffer不同,在內存分配上面,String直接使用v8堆存儲,不用經過c++堆外分配內存,并且Google也對String進行優化,在實際的拼接測速對比中,String比Buffer快。但是Buffer的出現是為了處理二進制以及其他非Unicode編碼的數據,所以在處理非utf8數據的時候需要使用到Buffer來處理。


編碼支持

  • ascii - 僅支持7位ASCII數據。

  • utf8 - 多字節編碼的Unicode字符

  • utf16le - 2或4個字節,小端編碼的Unicode字符

  • base64 - Base64字符串編碼

  • binary - 二進制編碼。

  • hex - 將每個字節編碼為兩個十六進制字符。

總結

以上是生活随笔為你收集整理的Node.js模块之Buffer的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。