zzzmj/duola-blog

深入理解Nodejs中的Buffer类

Opened this issue · 0 comments

zzzmj commented

前言

描述Buffer之前,先需要了解js的一些比较底层的原生知识

  • ArrayBuffer
  • Int8Array
  • TypedArray

ArrayBuffer

ArrayBuffer 对象来表示通用的,固定长度的原始二进制数据缓冲区。

简单说,ArrayBuffer就是一块内存,不方便直接用它,就像C语言 malloc申请一块内存,也会把它转换为实际上所需要的数组/指针来使用
它只是一堆01串,并不知道字节有多长,该用多少位去存

new ArrayBuffer(length): length代表申请ArrayBuffer的大小,单位为字节

Int8Array

我们可以通过Int8类型的数组,告诉ArrayBuffer,你需要将01串分割成以8位为一组的序列

就像这样
02_05-768x273.png

var buffer = new ArrayBuffer(1024)


var arr = new Int8Array(buffer) // 使用buffer创建一个8位的数组,

// 一个字节=8位,所以数组长度是1024

TypedArray

在js中,你找不到名为TypedArray的构造函数,其实它只是一个名称,是下面几个类型的统称

  • Int8Array();
  • Uint8Array();
  • Uint8ClampedArray();
  • Int16Array();
  • Uint16Array();
  • Int32Array();
  • Uint32Array();
  • Float32Array();
  • Float64Array();

简单说,它的作用就是告诉ArrayBuffer应该以怎样的形式来分离存放二进制字节

Buffer

有了前面的基础后,我们来看看node中的Buffer类

Buffer实例其实也是Uint8Array的实例,但是与TypedBuffer有一些微小的不同

例如:TypedBuffer.slice方法会创建一个新的数组拷贝
而Buffer.slice会在原先的数组上做修改

在Node 6.0之前,Buffer实例是由Buffer构造函数创建的

var buffer = new Buffer(10)

但是这种方式存在两个问题

  • 参数复杂,容易出错,传数字或者字符串或者ArrayBuffer会有不同的效应
  • 安全隐患,分配到的内存可能还存储着旧数据

具体的安全隐患例子:
第一个参数如果是100, new Buffer("100")会为字符串"100"分配三个字节的内存

本来我的程序中是默认接收字符串来分配内存的,但是攻击者如果恶意的传入很大的数字9999999999999

就会导致new Buffer(999999999999)申请了一个超大内存,导致内存耗尽,服务器奔溃

所以新的Buffer提供了四个方法来申请内存

  • Buffer.from()
  • Buffer.alloc()
  • Buffer.allocUnsafe()
  • Buffer.allocUnsafeSlow()

Buffer.from()

Buffer.from()是根据已有的数据创建Buffer实例,不接收数字为参数

Buffer.from(obj) // obj支持array, arrayBuffer, buffer, 

Buffer.alloc()

Buffer.alloc()是申请内存,

Buffer.alloc(size) // 分配size大小的内存,并填充为0

Buffer.allocUnsafe()和Buffer.allocUnsafeSlow()

这两者和alloc的区别就是

alloc会将字节填充为0,

这两个不会做填充,分配的内存没有初始化,可能是旧内存,所以不安全,也就更快了

使用Buffer

常见的就是对Buffer进行转换,转换为字符串转换为JSON,一般通过toXXX就可以实现了

Buffer的行为更类似于静态语言里的数组,而不像传统的js数组

如slice方法不会创建新数组,而是在原数组上做修改

长度一但确定就不会再发生改变

...

具体增删,读写,清空合并可以查API

更重要的是在流中,使用到了Buffer进行传输