GENEARE BY SD
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方法可以发送ArrayBufferBlod以及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, }这个就保证文件名先于文件数据到达

拓展

  1. 上面的例子文件是有大小限制的,如果过大就需要进行拆分,分别发送,否则会报错Failed to execute 'send' on 'RTCDataChannel': RTCDataChannel send queue is full
  2. 多文件传输还需要考虑文件分片交替的问题,我们可以在buffer中写入一部分数据用于标识分片数以及属于哪一个文件。

DONE