热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Node学习三、全局变量Buffer

全局变量之BufferBuffer一般称之为Buffer缓冲区。Buffer让JavaScript可以操作二进制。JavaScript语言起初服务于浏览器平台,
全局变量之 Buffer

Buffer 一般称之为 Buffer 缓冲区。

Buffer 让 Javascript 可以操作二进制。

Javascript 语言起初服务于浏览器平台,因此它内部主要操作的数据类型就是字符串。

Nodejs 的出现使得可以在服务端使用 Javascript 进行编程,完成 IO 操作,例如文件的读写、网络服务中数据的传输等,在这个过程中就是用到了 Buffer。

二进制数据

用户使用软件获取信息,开发者使用语言处理和展示信息,这个“信息”其实就是数据,例如在客户端上看到的字符、视频、图片、音频等。

无论我们当前看到的是什么,对于计算机来说,它处理的都是数字,也就是二进制。

IO 行为操作的就是二进制数据

流操作

Stream 流操作并非 Nodejs 独创,它本身已经存在很多年了。

可以将**“流”**理解为和字符串、数组类似的数据类型,用于存储数据,区别是它可以分段。

当进行大数据传输的时候就可以使用流操作,这样可以避免由于操作的数据内存过大。而出现的将内存占满的情况。

流操作配合管道技术,就可以将流当中的数据分段传输给下一个端,实现大数据的传输。

典型的应用场景就是现在我们看视频一般都是边下载边看。

Buffer

在这里插入图片描述

程序运行就会进行二进制的数据传输,而这个传输一般都是由 from 到 to 的过程,即数据的生产者和数据的消费者,中间就会使用流配合管道进行连接。

但是这个模型在实际工作的时候也会出现问题,比如数据的生产速度无法满足数据的消费速度,又或者数据的消费速度比生产速度慢了许多。

总归来说,不论出现哪种情况,数据都会有一个等待的过程,等待的时候那些多出来的数据,或者还不够一次消费的数据被存放在哪里呢?

这个时候就有了 Buffer,所以也称为 Buffer 缓冲区

Nodejs 中 Buffer 就是一片内存空间,只不过这个内存空间有些特殊。

Nodejs 中的代码最终都是由 V8 引擎执行完成的,因此理论上所有的内存消耗应该都属于 V8 的堆内存,而 Buffer 是 V8 之外的一片空间,它的大小不占据 V8 堆内存的大小。

通过 process.memoryUsage() 获取的内存消耗的信息中有一个 arrayBuffers,指的就是 Buffer 申请的内存。

Buffer 的空间申请不是由 Node 完成的,但是在使用层面上,它的空间分配又是由开发者编写的 JS 代码控制的,因此在空间回收的时候,它还是由 V8 的 GC(垃圾回收) 管理和回收,开发者无法参与其中。

Buffer 总结


  • Buffer 是 Nodejs 中的全局变量,无需 require
  • Buffer 使得可以在 Nodejs 平台下的操作二进制数据
  • Buffer 本身是一片内存空间,但是它不占据 V8 的堆内存大小,直接由 C++ 层面进行分配
  • Buffer 内存的使用由 Node 控制,由 V8 的 GC 回收,无法进行人为参与
  • Buffer 一般配合 Stream 流使用,充当数据缓冲区

创建 Buffer 实例

Buffer 是 Nodejs 内置的类,它相关的 API 其实就是这个类的静态方法。

有三种创建 Buffer 实例的方法:

  • Buffer.alloc(size[, fill[, encoding]]):创建默认填充0的指定字节大小的 buffer
  • Buffer.allocUnsafe(size):创建指定字节大小的 buffer(不安全的创建方法),不会向创建的内存填充数据
  • Buffer.from(...):接收数据,创建 buffer(与前两者的区别是创建默认带数据的 buffer)

为什么 allocUnsafe 不安全?

关键在于给 Buffer 申请分配的内存是否被初始化。被初始化的内存即填充了默认的数据,例如 0。没被初始化的内存可能包含敏感的旧数据,这是不安全的。

Buffer.alloc() 分配的内存是初始化过的内存(被 0 填满覆写),这种创建方式虽然慢但被认为是安全的。

Buffer.allocUnsafe() 分配的内存没有被初始化,所以分配速度相当快,但内存中可能存在敏感旧数据,在 Buffer 可读的情况下,可能会泄露数据,这种方式被认为是不安全的。一般会建议手动通过 buf.fill(0) 初始化或写满这个 Buffer。

虽然在使用 Buffer.allocUnsafe() 时有明显的性能优势,但必须额外小心,以避免给应用程序引入安全漏洞。

参考:Buffer(Buffer) - Buffer.from(), Buffer.alloc(), and Buffer.allocUnsafe()


为什么不使用 new 创建 Buffer?

在 Nodejs 的 v6 版本之前可以直接通过 new 实例化 Buffer 对象。

但是这种方式提供给 Buffer 实例对象的操作权限实在是太大了,所以在后续的版本中对它进行了一些处理。

主要还是使用这种方式分配的内存是没有初始化过的,包含敏感数据,Node.js 认为在分配内存的安全性上需要更加明确的区分,所以建议使用 Buffer 类的静态方法创建,而不是通过 new 实例化。

// 创建空间大小是 10 字节的 buffer
// buffer 会以16进制格式存储每个字节的数据
const b1 = Buffer.alloc(10)
const b2 = Buffer.allocUnsafe(10)
console.log(b1) //
console.log(b2)// from 的第一个参数可以接收3种数据类型:字符串 数组 buffer
const b3 = Buffer.from('中') // utf8 一个汉字用3个字节表示
console.log(b3) //
console.log(b3.toString()) // 中// from 的第一个参数如果是数组,数组元素应该都是数字格式(十进制、八进制或十六进制等),否则会被忽略
const b4 = Buffer.from([1, 2, '中']) // 汉字会被忽略
const b5 = Buffer.from([228/* 0xe4 的十进制 */, 0270/* 0xb8 的八进制 */, 0xad]) // 将汉字替换成数字
console.log(b4) //
console.log(b5) // // from 的第一个参数如果是 buffer,创建的 buffer 只是传入的 buffer 的拷贝,并不会共享空间
const b6 = Buffer.alloc(3)
const b7 = Buffer.from(b6)
b6[0] = 1
console.log(b6)
console.log(b7)

Buffer 实例方法

常用实例方法:

  • fill:向 buffer 中反复填充数据,直到填满,返回填充后的 buffer
  • write:向 buffer 中写入数据,返回写入的字节数
  • toString:根据指定的字符编码将 buffer 解码为字符串
  • slice:截取 buffer,类似数组的 slice
  • indexOf:类似数组的 indexOf
  • copy:从 buffer 数据源拷贝数据到目标 buffer 中

// 创建一个空的 buffer
const buf = Buffer.alloc(6)// fill
buf.fill('123') // 反复填充直到填满
console.log(buf) //
console.log(buf.toString()) // 123123
buf.fill('123456789')
console.log(buf.toString()) // 123456
buf.fill('0').fill('123', 1) // 第二个参数表示跳过填充的字节数
console.log(buf.toString()) // 012312
buf.fill('0').fill('123', 1, 3) // 第三个参数表示停止填充的位置索引(指定位置也不填充)
console.log(buf.toString()) // 012000
buf.fill(123) // 如果填充的是数字,则转化成十六进制填充
console.log(buf) //
console.log(buf.toString()) // {{{{{{

// 创建一个空的 buffer
const buf = Buffer.alloc(6)// write
// 与 fill 类似,但只会写入一次
buf.write('123')
console.log(buf) //
console.log(buf.toString()) // 123buf.fill(0).write('123', 1)
console.log(buf) // buf.fill(0).write('123', 1, 2) // 第三个参数是写入的字节数
console.log(buf) //

// 创建一个空的 buffer
const buf = Buffer.from('abc你好')// toString
// 第一个参数是解码的字符编码
// 第二个参数表示开始解码的字节索引位置
// 第三个参数表示停止解码的字节索引位置(不被解码)
console.log(buf) //
console.log(buf.toString()) // abc你好
console.log(buf.toString('utf8', 1, 6)) // bc你// slice
const b1 = buf.slice(1, 6)
console.log(b1) //
console.log(b1.toString()) // bc你// indexOf
// 返回 Buffer 中指定字符的字节位置索引
// 第二个参数时查找开始的位置
const b2 = Buffer.from('a你b好a你b好')
console.log(b2.indexOf('你')) // 1
console.log(b2.indexOf('b')) // 4
console.log(b2.toString().indexOf('b')) // 2
console.log(b2.indexOf('b', 5)) // 12

// copy
// buf.copy(target[, targetStart[, sourceStart[, sourceEnd]]])
// buf:复制的数据源 buffer
// target:目标 buffer
// targetStart:写入目标 buffer 的起始字节位置
// sourceStart:复制数据源 buffer 的起始字节位置
// sourceEnd:复制数据源 buffer 的结束字节位置(不包含)
// 复制的内容到指定 sourceEnd 或填充完目标 buffer 即结束const b1 = Buffer.from('你好abcde')
const b2 = Buffer.alloc(6)b1.copy(b2)
console.log(b1) //
console.log(b1.toString()) // 你好abcde
console.log(b2) //
console.log(b2.toString()) // 你好const b3 = Buffer.alloc(6)
b1.copy(b3, 2, 3, 7)
console.log(b3) //
console.log(b3.toString()) // 好

Buffer 静态方法

常用静态方法:

  • concat:将多个 buffer (数组)拼接成一个新的 buffer,便于获取多个 buffer 组成的数据
  • isBuffer:判断当前数据是否是 Buffer 类型

// concat
// 第一个参数是要拼接的 buffer 组成的数组
// 第二个参数是要限制的拼接结果的长度
const b1 = Buffer.from('你好')
const b2 = Buffer.from('世界')const b3 = Buffer.concat([b1, b2])
console.log(b3.toString()) // 你好世界const b4 = Buffer.concat([b1, b2], 9)
console.log(b4.toString()) // 你好世// isBuffer
console.log(Buffer.isBuffer([])) // false
console.log(Buffer.isBuffer('123')) // false
console.log(Buffer.isBuffer(b1)) // true

自定义 Buffer 的 split

Buffer 在使用上有很多地方和数组类似,例如下标操作、length 属性(Buffer 长度是固定的,无法修改)等。

不过目前并没有对 Buffer 提供拆分(split)操作,而这个操作在业务中又非常常见,所以这里利用 Buffer 本身提供的原生方法自定义一个 split 方法。

// 自定义 butter-split
Buffer.prototype.split = function (separator) {const len = Buffer.from(separator).length // 获取分割符字节数let res = [] // 最终返回结果let start = 0 // 查询起始位置let offset = 0 // 偏移量while ((offset = this.indexOf(separator, start)) !== -1) {res.push(this.slice(start, offset))start = offset + len}// 追加尾部res.push(this.slice(start))return res
}const buf = Buffer.from('夫战,勇气也,一鼓作气,再而衰,三而竭,彼竭我盈,顾克之,')console.log(buf.split(',').map(v => v.toString()))


推荐阅读
  • 浅解XXE与Portswigger Web Sec
    XXE与PortswiggerWebSec​相关链接:​博客园​安全脉搏​FreeBuf​XML的全称为XML外部实体注入,在学习的过程中发现有回显的XXE并不多,而 ... [详细]
  • Windows7企业版怎样存储安全新功能详解
    本文介绍了电脑公司发布的GHOST WIN7 SP1 X64 通用特别版 V2019.12,软件大小为5.71 GB,支持简体中文,属于国产软件,免费使用。文章还提到了用户评分和软件分类为Win7系统,运行环境为Windows。同时,文章还介绍了平台检测结果,无插件,通过了360、腾讯、金山和瑞星的检测。此外,文章还提到了本地下载文件大小为5.71 GB,需要先下载高速下载器才能进行高速下载。最后,文章详细解释了Windows7企业版的存储安全新功能。 ... [详细]
  • 渗透测试基础bypass绕过阻挡我们的WAF(下)
    渗透测试基础-bypass ... [详细]
  • 本文介绍了Python高级网络编程及TCP/IP协议簇的OSI七层模型。首先简单介绍了七层模型的各层及其封装解封装过程。然后讨论了程序开发中涉及到的网络通信内容,主要包括TCP协议、UDP协议和IPV4协议。最后还介绍了socket编程、聊天socket实现、远程执行命令、上传文件、socketserver及其源码分析等相关内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Voicewo在线语音识别转换jQuery插件的特点和示例
    本文介绍了一款名为Voicewo的在线语音识别转换jQuery插件,该插件具有快速、架构、风格、扩展和兼容等特点,适合在互联网应用中使用。同时还提供了一个快速示例供开发人员参考。 ... [详细]
  • 背景应用安全领域,各类攻击长久以来都危害着互联网上的应用,在web应用安全风险中,各类注入、跨站等攻击仍然占据着较前的位置。WAF(Web应用防火墙)正是为防御和阻断这类攻击而存在 ... [详细]
  • 目录浏览漏洞与目录遍历漏洞的危害及修复方法
    本文讨论了目录浏览漏洞与目录遍历漏洞的危害,包括网站结构暴露、隐秘文件访问等。同时介绍了检测方法,如使用漏洞扫描器和搜索关键词。最后提供了针对常见中间件的修复方式,包括关闭目录浏览功能。对于保护网站安全具有一定的参考价值。 ... [详细]
  • 篇首语:本文由编程笔记#小编为大家整理,主要介绍了VoLTE端到端业务详解|VoLTE用户注册流程相关的知识,希望对你有一定的参考价值。书籍来源:艾怀丽 ... [详细]
  • OWASP(安全防护、漏洞验证工具)开放式Web应用程序安全项目(OWASP,OpenWebApplicationSecurityProject)是一个组织 ... [详细]
  • 深入浅出工控机加密
    工控机痛点在于不连外网,操作系统无法打补丁,病毒库无法更新,普通杀毒软件无用;因为是专用设备,用户的网管不敢在 ... [详细]
  • 【CTF 攻略】第三届 SSCTF 全国网络安全大赛—线上赛 Writeup
    【CTF 攻略】第三届 SSCTF 全国网络安全大赛—线上赛 Writeup ... [详细]
  • Linux神奇漏洞:长按回车键70秒 即可轻松拿到Root权限
    一般来说获取系统root权限是很困难的,尤其是加密系统中,但西班牙安全研究员hectormarco、ismaelripoll发现,linux系统下只需按住回车键70秒钟,就能轻 ... [详细]
  • 生成对抗式网络GAN及其衍生CGAN、DCGAN、WGAN、LSGAN、BEGAN介绍
    一、GAN原理介绍学习GAN的第一篇论文当然由是IanGoodfellow于2014年发表的GenerativeAdversarialNetworks(论文下载链接arxiv:[h ... [详细]
author-avatar
国民男神-权志龙
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有