【发布时间】:2016-05-16 19:52:11
【问题描述】:
请原谅我提出这个愚蠢的问题,但对于 NodeJS 中的流式传输有什么大惊小怪的问题,我有点困惑。
我知道流式传输允许我们一次发送大量数据,从而改善最终用户的体验
但是,这不是在 Internet 上传输数据的标准方式吗?哪里,客户端和服务端建立了socket连接,数据通过包发送?
套接字 == 流 && 和数据包 == 块,对吗?
【问题讨论】:
标签: node.js sockets tcp stream
请原谅我提出这个愚蠢的问题,但对于 NodeJS 中的流式传输有什么大惊小怪的问题,我有点困惑。
我知道流式传输允许我们一次发送大量数据,从而改善最终用户的体验
但是,这不是在 Internet 上传输数据的标准方式吗?哪里,客户端和服务端建立了socket连接,数据通过包发送?
套接字 == 流 && 和数据包 == 块,对吗?
【问题讨论】:
标签: node.js sockets tcp stream
这根本不是重点。
你是对的,通过 TCP/IP 通信的点对点 HTTP 传递一系列数据包。
但请考虑允许您查看部分文件的网站,而不是强制您等待整个文件准备好后再开始播放的网站。
不同之处在于客户端和服务器同意的是“完整”文档。
在最后一个示例中,文件是完整的文档。 服务器无法(/不愿意)提供比完整文件更精细的文档;因此,您的浏览器必须等到整个文件下载完成后,才能舒适地使用它。
在另一个宇宙中,一个完整的“文档”可能是一组字节,这些字节与标题信息一起传回,指定这些字节在整个文件中的位置,允许在文档中查找,当你有部分时播放内容等等。 当播放器的缓冲内容用完时,它将寻找下一部分,该部分恰好是由另一组字节组成的资源,从当前内容之后的字节开始。
不过,这与 Node 关系不大,更多的是与 HTTP1.1 相关
其他形式的套接字连接(WebSockets、UDP 等)具有不同的行为和期望。
与 Node 关系不大,尽管 Node 的流确实可以轻松地支持服务器之间的流式通信,以及一种或另一种形式的客户端之间的流式通信,无论是否通过 HTTP。
好的,这样就可以遮盖住了…… ...如果不是专门针对分块通信,那么节点“流”是什么?
要掌握这一点,最简单的方法是从基于集合(/集合)的编程概念开始。
曾几何时,如果我有一个想要加倍的数字列表,我可能会写如下内容:
var numbers = [1, 2, 3];
var number;
var doubles = [];
var i = 0,
l = numbers.length;
for (; i < l; i += 1) {
number = numbers[i];
doubles.push( number * 2 );
}
不过,这些天来,我会使用 .map 来删除所有循环管理,而只专注于我想应用于每个元素的微小原子操作:
const numbers = [1, 2, 3];
const doubles = numbers.map(x => x * 2);
对吗? 这大大降低了复杂性。当然,如果我想继续在后面链接额外的变换,我可以。
numbers
.map(double)
.map(add1)
.filter(gt5)
.map( ... ) // etc
所以现在您看到,功能更强大、基于集合的编程就是一次声明一个操作,一次声明一个元素...... ...流从何而来?
嗯... ...如果您正在映射和过滤(和减少)的数组没有完成怎么办? 如果它在系统运行时被其他进程异步填充怎么办?
它可能通过分块的 HTTP1.1 流量填充,当然... ...但这远非必需。相反,它可以由超时、系统操作、数据库或其他任何事物来填充。
如果我有一个神奇的服务,它给了我一个流,我可能会这样使用它:
// returns a stream which fires on *every* returned row
db.streamQuery( "select * from ........" )
// turned into domain objects in your system
.pipe( transformRecordIntoObject )
// remove private data (DB keys, admin properties, whatever)
.pipe( removeInternalObjectProperties )
// remove entries which aren't wanted/helpful, for one reason or another
.pipe( filterOutUnwantedEntries )
// buffer entries up, to serve an array of 100 at a time
.pipe( bufferEvery100AsJSON )
// send the JSON of 100 results (at a time) straight to the client who requested them
.pipe( res );
如您所见,流本身(提供.pipe,接受连接流)与 HTTP 通信关系不大...
...也就是说,它们非常适合,并且您在 HTTP 请求中拥有的 req 和 res 对象确实分别是可读和可写流,因此,您可以从/到它们的管道,以这种方式。
我有意跳过特定的实现细节,以及尾部的特定通信要求,我通过网络传输 JSON 位... ...对于典型的 HTTP 响应(包括基于范围的内容流),这将需要更多的工作,但对于 ServerSent 事件来说,不会有比这更多的工作。
我希望这有助于解释您可能预期的内容与您一直在阅读的内容之间的一些差异......以及流式套接字通信和功能流之间的一些交叉可能可以在 Node 和 Scala、Bash|Powershell|etc 中的终端命令管道以及其他一些地方找到。
【讨论】: