thuck: 极其简单的一层协议 / Node.js Stream API 实现实战

其实,这篇文章我主要想分享 Node.js 的 Stream API 的实现的。。。讲着讲着跑题了

这几天在写一个小玩意,需要在 Android 上将一份一份的数据通过 WiFi 传输到电脑。电脑上的服务端使用 Node.js 搭建。

众所周知,TCP 中传输的数据会被切分成较小的包,客户端往 Socket 一次写入的数据,在另一头的服务器端并不是一次读出的。具体在 Node.js 中的现象就是,多次发生 'data' 事件,每次只带了很小一片数据。因此如何将这些小片数据重新组合在一起成了一个问题。

由于客户端运行在手机上,因此决定封一个极其简单的协议:thuck(好吧项目名字已经代表了我当时的心情了)。

首先,分析一下现在遇到的问题:大块数据被切分成了很小的包,小块数据有可能被和前面或后面的小包合并了。一份数据在哪里结束?下一份数据由从哪里开始?

目前我的解决方案是这样的:

客户端传递数据前,先传一个标志,以及接下来这份数据的长度;服务器端捕获到标志及长度后,开始收集这么一段长度的数据,收集完毕后合并输出。为了简单,这里有几个约定:

  • 为了不用遍历整个数据包,约定第一个包的一开始就应该是标志。
  • 标志约定就只有一个字节,经跟着是 32 位(4 字节)无符号整数表示的数据长度。
  • 标志和长度组成了 5 个字节的头,假设这 5 个字节的头部不会被系统切断。

理想中的一份数据是这样的:

[AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]
[BBBBBBBBBBBBBBB]
[CCCCCCCCCCCCCCCCCCCCC]
[DDDDDDD]

于是,按照我们的这个「协议」加上头后的数据是这样的:

[FA][LENGTHAA][AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]
[FB][LENGTHBB][BBBBBBBBBBBBBBB]
[FC][LENGTHCC][CCCCCCCCCCCCCCCCCCCCC]
[FD][LENGTHDD][DDDDDDD]

实际情况中,假设分包的大小不可知,传输的数据可能会是这样的:

[FA][LENGTHAA][AAAAAAAAAAAAAAAAAAAAAAA]
[AAAAAAAAAA][FB][LENGTHBB][BBBBBBBBBBB]
[BBBB][FC][LENGTHCC]
[CCCCCCCC]
[CCCCCCCCCCCCC][FD][LENGTHDD]
[DDDDDDD]

可能更悲催的,会把你的头也截断。。。这,想太多了,RP 不好就默哀吧。

貌似讲太多了,直接操家伙动手吧

TCP Socket 在 Node.js 中被封装成了 Stream 接口的一个衍生;而我对这些数据的使用也是流式使用。进去出来都是 Stream,因此我们可以借助 stream 模块的 Transport 抽象类实现一个转换器。

stream.Transform 是一个抽象类,意思就是本身不能直接使用,而是需要继承并重写对应的方法。在 Node.js 中类的继承可以用 util 模块中的 inherits 函数:

var inherits = require('util').inherits
  , Transform = require('stream').Transform

module.exports = Thuck
inherits(Thuck, Transform)

最近 SF 的代码块有点内啥,扫兴。直接看完整源代码吧。

https://github.com/xingrz/thuck/blob/master/lib/thuck.js

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