Node.js流Stream如何解决字符串编码问题

这几天在开发P2P,使用了LibP2P作类库,在peer和peer通信过程遇到了一些问题,从一个peer传输到另一个peer的json字符串无法尽心JSON.parse。

苦思良久,原来还是对流的概念没有学好,LipP2P的通信是采用流的方式交互的,所以输入的字符串是可能出现损坏的,尤其是中文,尤其是中文!必须强调的是我在第一次测试英文传输是没有出现问题,直到我输入了“你好”两个字,就出现了JSON.parse的“unexpected token error“。

解决思路很简单,那就是利用编码encode这段字符串(无论是普通字符串还是json格式的)。编码有很多种类,node里的Buffer对象为我们提供了如下这些编码:
Buffer的编码方式
其实应该是任选一项都可以的哈,但是选择了base64,毕竟base是web较为通用的encode方式,其他的我没有做测试哈,大家自行测试。

选择base64之后,就是进行通信的两个peer的流的encode和decode,一个是dial端(发送),一个是handle端(接收端),代码分别如下:

接收端:

function handle(action: string, callback: MessageCallback): void {
    this.node.handle(action, async ({ stream }) => {
        const msg = await pipe(stream, concat)
        const str = Buffer.from(msg.toString(), 'base64').toString('utf8')
        callback($.msgParse(str))
    })
}

发送端:

async function send(action: string, msg: Message, peer: Peer[] = []): Promise<void> {
    if (!peer.length) peer = await this.getPeer()
    // send my peer to the p2p network(every one)
    for (const item of peer) {
        // skip myself
        if (this.isMyPeer(item.address)) continue
        this.node
            .dialProtocol(`${item.address}/p2p/${item.id}`, action)
            .then(({ stream }) => pipe(Buffer.from($.msgStringify(msg)).toString('base64'), stream))
            .catch(e => {
                console.log(e)
                console.log('Disconnect', item.address)
                this.killPeer(item)
            })
    }
}

其实在java和C++中的流也是存在这个字符类型的问题的。这里不做介绍了,总结一下就是当使用到流的时候,最好是要做encode和decode操作,尤其是unicode系的编码,里面还有一些emoji表情啥的。

posted @ 2021-04-02 11:09  devilyouwei  阅读(254)  评论(0编辑  收藏  举报