深入理解 Stream (Node.js)

一直在思考 Nodejs 除了高效的异步IO 还有哪些东西是值得花更多多时间去理解的呢?

进程通讯,内存管理,异步流程控制,[Stream],node 模块

以下是废话可以略过

个人认为Nodejs是应对io密集,高并发,高性能需求应用的最佳选择之一。
Nodejs 使用 libuv (在windows平台使用IOCP, 在FreeBSD上使用`kqueue`,在*nux上使用[e]poll)。使得Nodejs在各种平台上具有相同的性能, 这点与python的Tornado,nginx不同。

Nodejs 两大特点

Feature — 使用了 unix:socket 进程通讯模型。可以使用unix程序的实际思路,将大的程序产分成小的模块,最终使用进程间通讯的机制将小的模块程序连接在一起,形成统一的服务。可以轻松实现高可用高性能的集群。

Feature — Stream 具有异步的特性。我么可以将一个文件或一段内容分为未知个制定大小的 chunk 去读取,每读取到一个 chunk 我们就将他输出。直到文件读完。这就像 http1.1 种支持的 Transfer-Encoding: chunked那样。 (chunk可以以任何的形式存在,Nodejs 默认是以Buffer的形式存在,这样更高效)。Nodejs 中的Stream具备Unix系统上的一个超级特性就是 (pipe -- 管道)

说起 Nodejs 中的 流不得不谈起 *nix 系统.(可能是应为 nodejs 的设计者大量借鉴了性能出色的unix底层设计)

unix 下使用管道的可以高效的帮我们完成工作

$ ~ -> cat /etc/passwd | grep admin # 查看系统中用户的详细信息
$ ~ -> ps aux | grep sshd #查看 sshd 进程基本运行状况

这样一条命令执行后 你的电脑就可以通过ssh证书形式登陆远程终端。

$ ~ -> ssh yin@8.8.8.8 'cat >> ~/.ssh/authorized_keys' < ~/.ssh/id_rsa.pub

这就是一个 将本地的 id_rsa.pub 文件以流的形式 发送给 远程主机(8.8.8.8)的cat程序,并以用户 yin 的身份将 流写入到 /homeyin/.ssh/authorized_keys文件中。这个过程是非常高效的。

同样 nodejs 的 strame 也是这样工作的。 | 管道符在node中是使用 pipe() 来提供的。 ‘small-program design and unix philosophy’ 这与node的设计非常契合。

好的让我们从现在开始探讨nodejs中的stream吧。

还记得 第一个 nodejs hello,world http server吗?

 var http = require('http');
 var server = http.createServer(function(req, res){
    res.writeHeader(200, {'Content-Type': 'text/plain'});
    res.end('hello, world');
 });
 server.listen(8080);
 console.log('http server running on port 8080 ...');

后来我们有学习到了,fs 中的 readFile 方法,终于可以讲一个文件以超文本或超媒体的像是发送到浏览器了。

于是 …

#server.js
...
  fs.readFile(__dirname + '/data.html', 'utf-8', function(err, data){
      if(err) {
          res.writeHeader(500, {'Context-Type': 'text/plain'});
          res.end('specify file not exists! or server error!');
      }
      else{
        res.writeHeader(500, {'Context-Type': 'text/html'});
        res.end(data);
      }
  })
...
#data.html
<html>
    <head>
        <style type="text/css">
            div {
                margin-top: 50px;
                width: 100px; margin: 0 auto;
                padding: 5px; border: 1px solid #ccc;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div>my first static file server!</div>
    </body>
</html>

现在我们需要思考一下,如果 我们要发送的不是一个单纯的文本文件而是超媒体文件比如说 Google 2014 IO 大会 的全程高清视频文件 .mp4 格式。长度2个多小时1080p。大概4个多GB。

已知 readFile 的工作方式是将文件读取到内存。那么这么大一个文件显然是不能这么做的。那该怎么办呢?是之后就需要使用 strame 的来做。那么是这样的。

...
    fs.createReadStream(__dirname + '/vedio.mp4').pipe(res)
...

代码很短,没有回调,是的。

我们查看 response 的 header 的话。 node server 会自动帮我们加上这样的标头.

Connection: Keep-Alive
Transfer-Encoding: chunked

我们是使用 持久连接 以 chunk 的形式 将我们的视频文件发送到我们的客户端。这是一个直观的形式。

接着看,请移步 GitHub。如果你想深入许学习 nodejs 这篇文章你不能错过

    原文作者:东来
    原文地址: https://segmentfault.com/a/1190000002395759
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞