这几天在开发P2P,使用了LibP2P作类库,在peer和peer通信过程遇到了一些问题,从一个peer传输到另一个peer的json字符串无法尽心JSON.parse。
苦思良久,原来还是对流的概念没有学好,LipP2P的通信是采用流的方式交互的,所以输入的字符串是可能出现损坏的,尤其是中文,尤其是中文!必须强调的是我在第一次测试英文传输是没有出现问题,直到我输入了“你好”两个字,就出现了JSON.parse的“unexpected token error“。
解决思路很简单,那就是利用编码encode这段字符串(无论是普通字符串还是json格式的)。编码有很多种类,node里的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表情啥的。