Ошибка соединения PeerJS/WebRTC при быстрой передаче фрагментов

Я использую PeerJS, но думал, что эта проблема может быть связана с WebRTC в целом, надеюсь, вы можете мне помочь:

Я пытаюсь написать простой одноранговый файлообменник. Я использую serialisation: "none" для PeerJS соединения DataChannel, так как отправляю только чистые ArrayBuffers.
Все хорошо с файлами размером около 10 МБ, но у меня проблемы с отправкой файлов большего размера (30+ МБ), например, после отправки около 10-20 первые куски соединения zip-файла размером 900 МБ между узлами начинают выдавать Connection is not open. You should listen for the "open" event before sending messages. (со стороны Sender)

Моя установка:

Файл перетаскивается для перетаскивания, Sender использует FileReader для чтения его как ArrayBuffer кусками по 64x1024 байт (без разницы с 16x1024), и как только каждый кусок прочитан - он отправляется через 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 мс между передачами фрагментов немного помогла, загрузка файла размером 900 МБ достигла 6 % (вместо 1–2 % ранее), после чего начались ошибки. Может быть, это какой-то предел одновременных операций через datachannel или переполнение какого-то datachannel буфера?
Обновление1: Вот мой объект подключения PeerJS с объектом DataChannel внутри него:
Визуализация объектов в Google Chrome


person Max Yari    schedule 27.05.2015    source источник
comment
В какой-то момент у меня была такая же проблема, но ее больше нет. Мой код закончился на github, но написан дротиками . может поможет! Я добавил {'ordered': true, 'reliable': true} к createDataChannel, может быть, это поможет?   -  person Robert    schedule 28.05.2015
comment
@ Роберт, к сожалению, это не помогло, «упорядоченный» и «надежный» уже истинны в объекте DataChannel внутри моего объекта соединения peerjs. Сейчас я добавлю свой объект соединения к вопросу, можете ли вы бросить сюда свой, чтобы я мог сравнить два?   -  person Max Yari    schedule 28.05.2015
comment
есть ссылка на мой код github. Я не использую peerjs, поэтому я не могу вам здесь помочь :( Для меня FileReader занимает ~ 25-50 мс, чтобы преобразовать большой двоичный объект в bytearray, и кажется, что этого достаточно, чтобы заставить его работать для меня.   -  person Robert    schedule 28.05.2015
comment
@Robert Я имел в виду объект подключения, который создается во время выполнения, когда вы подключаетесь к другому узлу, который вы используете для отправки сообщений. Конечно, если у вас есть легкий доступ к нему прямо сейчас. Честно говоря, настройка localhost для запуска вашего кода для просмотра одного объекта — это немного хлопот.   -  person Max Yari    schedule 28.05.2015
comment
DataChannel выглядит идентично.   -  person Robert    schedule 28.05.2015
comment
@ Роберт, ну, это грустно   -  person Max Yari    schedule 28.05.2015


Ответы (1)


Всем хороших новостей!
Это была проблема с переполнением буфера DataChannel, спасибо за эту статью http://viblast.com/blog/2015/2/25/webrtc-bufferedamount/

bufferedAmount - это свойство объекта DataChannel(DC), которое в последней версии Chrome отображает количество данных в байтах, находящихся в данный момент в буфере, когда оно превышает 16 МБ - DC закрывается без уведомления. Поэтому любой, кто столкнется с этой проблемой, должен реализовать механизм буферизации на уровне приложения, которое будет следить за этим свойством и при необходимости удерживать сообщения. Также имейте в виду, что в версиях Chrome до 37 это же свойство отображает количество (не размер) сообщений, и более того, оно сломано под окнами и отображает 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

person Max Yari    schedule 31.05.2015