PeerJS/WebRTC连接在快速传输大块数据时失败

15

我正在使用PeerJS,但认为这个问题可能与WebRTC有关,希望您能帮助我解决:

我正在尝试编写一个简单的点对点文件共享程序。我在PeerJS连接DataChannel中使用serialisation: "none",因为我只发送纯的ArrayBuffers
一切都很好,对于大约10MB左右的文件,但是发送更大的文件(30MB以上)时出现问题,例如,在发送大约10-20个900MB zip文件块后,对等方之间的连接开始抛出Connection is not open. You should listen for the "open" event before sending messages。(在Sender端)

我的设置:

将文件拖到拖放区域,Sender使用FileReader以64×1024字节的块读取它作为ArrayBuffer(使用16×1024没有区别),并在每个块读取完毕后立即通过peer.send(ChunkArrayBuffer)发送。

Reciever从每个接收到的块创建blob,传输完成后将它们组合成完整的blob,并提供链接给用户。

我的节点连接设置:

   var con = peer.connect(peerid, {
        label: "file",
        reliable: true,
       serialization: "none"
   })

我的发送函数:

function sliceandsend(file, sendfunction) {
    var fileSize = file.size;
    var name = file.name;
    var mime = file.type;
    var chunkSize = 64 * 1024; // bytes
    var offset = 0;

 function readchunk() {
    var r = new FileReader();
    var blob = file.slice(offset, chunkSize + offset);
    r.onload = function(evt) {
        if (!evt.target.error) {
            offset += chunkSize;
            console.log("sending: " + (offset / fileSize) * 100 + "%");
            if (offset >= fileSize) {
                con.send(evt.target.result); ///final chunk
                console.log("Done reading file " + name + " " + mime);
                return;
            }
            else {                    
                con.send(evt.target.result);
            }               
        } else {
            console.log("Read error: " + evt.target.error);
            return; 
        }
        readchunk();
       };
        r.readAsArrayBuffer(blob);
    }
    readchunk();
  }
有什么想法可以导致这种情况发生吗?
更新:在分块传输之间设置50毫秒的超时有所帮助,900mb的文件加载在开始抛出错误之前达到了6%(之前只有1-2%)。也许这是通过数据通道进行的同时操作的某种限制或溢出某种数据通道缓冲区的问题?
更新1:这是我的PeerJS连接对象,里面包含DataChannel对象:
Object visualization in Google Chrome

2
我曾经也遇到过同样的问题,但现在已经没有了。我的代码存放在 github,写的是dart语言。或许对你有所帮助!我在createDataChannel中添加了{'ordered': true, 'reliable': true},也许会有所帮助? - Robert
@Robert,很遗憾这并没有帮助,DataChannel对象中的“ordered”和“reliable”已经是true了,而且它们在我的peerjs连接对象中。我现在会将我的连接对象添加到问题中,你能否把你的连接对象也放在这里,这样我就可以比较一下两个对象? - Max Yari
这是我的Github代码链接。我没有使用PeerJS,所以在这里我无法提供帮助:( 对我来说,FileReader需要大约25-50毫秒将Blob转换为字节数组,这似乎足以让它对我起作用。 - Robert
@Robert 我的意思是在运行时创建连接对象,当你连接到另一个对等方时,你使用它来发送消息。当然,如果你现在可以轻松访问它的话。将localhost设置为运行代码以查看一个对象有点麻烦。 - Max Yari
数据通道看起来完全一样。 - Robert
@Robert 嗯,那很遗憾。 - Max Yari
2个回答

8

大家好,有好消息!
这是一个DataChannel问题的缓冲区溢出,感谢这篇文章http://viblast.com/blog/2015/2/25/webrtc-bufferedamount/

bufferedAmountDataChannel(DC)对象的一个属性,在最新版本的Chrome中,它显示当前缓冲区中以字节为单位的数据量,当超过16MB时,DC会被静默关闭。 因此,任何遇到此问题的人都需要在应用程序级别实现缓冲机制,观察此属性并在必要时暂停消息。另外,请注意,在Chrome 37之前的版本中,相同的属性显示的是数量而不是大小,并且在Windows下是错误的,并显示为0,但是在v<37上溢出DC不会关闭-只会抛出异常,也可以捕获以指示缓冲区溢出。

我编辑了peer.js未压缩代码,这里您可以看到两种方法在一个函数中(更多源代码可以查看https://github.com/peers/peerjs/blob/master/dist/peer.js#L217

DataConnection.prototype._trySend = function(msg) {
var self = this;
function buffering() {
    self._buffering = true;
    setTimeout(function() {
        // Try again.
        self._buffering = false;
        self._tryBuffer();
    }, 100);
    return false;
}
if (self._dc.bufferedAmount > 15728640) {
    return buffering(); ///custom buffering if > 15MB is buffered in DC 
} else {
    try {
        this._dc.send(msg);
    } catch (e) {
        return buffering(); ///custom buffering if DC exception caught
    }
    return true;
 }        
}

还在PeerJS的GitHub上开了一个问题:https://github.com/peers/peerjs/issues/291


0

请查看传输文件

此页面显示如何通过WebRTC数据通道传输文件。

为了以互操作的方式完成这个目标,文件被分成块,然后通过数据通道传输。数据通道默认是可靠和有序的,非常适合文件传输。

尽管它不使用peerjs,但它可以适应(使用peerjs),代码易于理解,并且没有任何问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接