- Published on
WebRTC - 尝试 - 第三章
用一下createDataChannel
发送一个小文件
创建channel
const dc = rtcPeerconnectionRef.current.createDataChannel('file', {
ordered: true,
})
dc.onopen = () => {
console.log('open')
}
onopen
事件会在建联成功后触发,我们也需要在建联之前创建dataChannel
响应channel
peerConnection.ondatachannel = (e) => {
e.channel.onmessage = (e) => {
//handle message
}
}
当datachannel建立后会收到ondatachannel
回调,我们可以在参数中拿到channel对象,并添加一个回调函数onmessage
用于处理通过datachannel
收到的消息。
发送文件
获取文件可以用input,这里就不说了。
const someFile = someHowYouGetYourFile()
const reader = new FileReader()
reader.onload = (event) => {
dataChannel.send(event.target?.result as ArrayBuffer)
}
dataChanne.send(someFile.name)
reader.readAsArrayBuffer(someFile)
dataChannel
上的send
方法可以发送ArrayBuffer
、Blod
以及string
类型的数据,但是发现Blod
类型会报错,所以这里会转成ArrayBuffer
。 这里我们先发送了文件名,因为通过ArrayBuffer
是无法获得原始文件的文件名的。
接收文件
在对端我们接收一下文件,就在刚刚的onmessage
中处理
peerConnection.ondatachannel = (e) => {
e.channel.onmessage = (e) => {
if (typeof e.data === 'string') {
fileName.current = e.data
}
if (e.data instanceof ArrayBuffer) {
const blob = new Blob([e.data])
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = fileName.current
a.click()
URL.revokeObjectURL(url)
}
}
}
这里我们判断了一下收到的数据的类型,如果是string
,就当作文件名,如果是ArrayBuffer
就当作文件的数据,最后恢复成文件。
在createDataChannel
中我们指定了{ ordered: true, }
这个就保证文件名先于文件数据到达
拓展
- 上面的例子文件是有大小限制的,如果过大就需要进行拆分,分别发送,否则会报错
Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel send queue is full
- 多文件传输还需要考虑文件分片交替的问题,我们可以在buffer中写入一部分数据用于标识分片数以及属于哪一个文件。
DONE