1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
|
---
title: Использование каналов данных в WebRTC
slug: Web/API/WebRTC_API/Using_data_channels
translation_of: Web/API/WebRTC_API/Using_data_channels
---
<p>{{WebRTCSidebar}}{{draft}}</p>
<p>Как только WebRTC соединение установлено, используя интерфейс {{domxref("RTCPeerConnection")}}, приложение в состоянии отправлять и получать медиаданные между двумя узлами в соединении. Но от WebRTC можно получить больше. В этом руководстве мы изучим то, как добавить канал данных в соединение, который будет использован для безопасной передачи произвольных данных (данных любого типа, в любом формате).</p>
<div class="note">
<p> Поскольку все компоненты WebRTC требуют использования кодирования, любые данные, передаваемые через <code>RTCDataChannel</code> автоматически защищаются, используя Datagram Transport Layer Security (<strong>DTLS</strong>). Смотри {{anch("Security")}} ниже для подробной информации.</p>
</div>
<h2 id="Создание_канала_данных">Создание канала данных</h2>
<p>Основной транспорт передачи данных, использующийся объектом типа {{domxref("RTCDataChannel")}} может быть создан двумя способами:</p>
<ul>
<li>Позволить WebRTC создать транспорт и сообщить об этом удалённому узлу (вызвав у него событие типа {{event("datachannel")}} ). Это простой способ, и он подходит для многих случаев, но не достаточно гибок для широких нужд.</li>
<li>Написать свои скрипты по согласованию транспорта данных, и сигнализированию другому узлу о необходимости присоединения к новому каналу данных.</li>
</ul>
<p>Разберём оба случая, начиная с первого, как с наиболее распространенного.</p>
<h3 id="Автоматический_режим_согласования">Автоматический режим согласования</h3>
<p>Зачастую, разработчик может позволить объекту соединения обработать согласование {{domxref("RTCDataChannel")}} соединения за него. Для этого нужно вызвать метод {{domxref("RTCPeerConnection.createDataChannel", "createDataChannel()")}} без определения значения свойства {{domxref("RTCDataChannelInit.negotiated", "negotiated")}}, или определить свойство значением <code>false</code>. Это автоматически активирует <code>RTCPeerConnection</code> на обработку согласования соединения за разработчика, вызывая событие создание канала данных у удалённого узла, связывая два узла вместе по сети.</p>
<p>Вызов метода <code>createDataChannel()</code> немедленно возвращает объект типа <code>RTCDataChannel</code>. Подписываясь на событие {{domxref("RTCDataChannel.open_event", "open")}} , можно будет точно определить когда соединение успешно откроется.</p>
<pre class="brush: js">let dataChannel = pc.createDataChannel("MyApp Channel");
dataChannel.addEventListener("open", (event) => {
beginTransmission(dataChannel);
});
</pre>
<h3 id="Ручной_режим_согласования">Ручной режим согласования</h3>
<p>Для ручного согласования соединения, сначала необходимо создать новый объект типа {{domxref("RTCDataChannel")}}, используя метод {{domxref("RTCPeerConnection.createDataChannel", "createDataChannel()")}} объекта {{domxref("RTCPeerConnection")}}, определяя свойство {{domxref("RTCDataChannelInit.negotiated", "negotiated")}} в значение <code>true</code>. Это сигнализирует объекту соединения не пытаться согласовать соединение автоматически.</p>
<p>Затем нужно согласовать соединение, используя веб сервер или иные средства коммуникации. Этот процесс должен сигнализировать удалённому узлу, что нужно создать собственный объект типа <code>RTCDataChannel</code> со свойством <code>negotiated</code>, установленным в значение <code>true</code>, используя тот же идентификатор канала {{domxref("RTCDataChannel.id", "id")}}. Это свяжет два объекта типа <code>RTCDataChannel </code>через объект типа <code>RTCPeerConnection</code>.</p>
<pre class="brush: js">let dataChannel = pc.createDataChannel("MyApp Channel", {
negotiated: true
});
dataChannel.addEventListener("open", (event) => {
beginTransmission(dataChannel);
});
requestRemoteChannel(dataChannel.id);</pre>
<p>В данном примере канал создаётся установкой значения свойства <code>negotiated</code> в <code>true</code>, затем вызывается функция <code>requestRemoteChannel()</code> , запуская согласование соединения для создания удалённого канала с тем же идентификатором как у локального канала. Таким образом создание каналов данных позволяет использовать различные свойства, создавая их декларативно, используя одно и тоже значение идентификатора канала <code>id</code>.</p>
<h2 id="Буферизация">Буферизация</h2>
<p>Каналы данных WebRTC поддерживают буферизацию исходящих данных. Это работает автоматически. Несмотря на то, что нет способа контролировать размер буфера, вы можете узнать, сколько данных в настоящее время буферизуется, и вы можете выбрать уведомление о событии, когда в буфере начинают заканчиваться данные в очереди. Это облегчает написание эффективных подпрограмм, которые гарантируют, что всегда есть данные, готовые к отправке, без чрезмерного использования памяти или полного переполнения канала. </p>
<p><strong><<<write more about using bufferedAmount, bufferedAmountLowThreshold, onbufferedamountlow, and bufferedamountlow here>>></strong></p>
<p>...</p>
<h2 id="Ограничения_размеров_сообщений">Ограничения размеров сообщений</h2>
<p>Для любых данных, передаваемых по сети, существуют ограничения по размеру. На фундаментальном уровне отдельные сетевые пакеты не могут быть больше определённого значения (точное число зависит от сети и используемого транспортного уровня). На уровне приложения, то есть в пределах {{Glossary("user agent", "user agent's")}} реализация WebRTC, в которой работает ваш код, реализует функции поддержки сообщений, размер которых превышает максимальный размер пакета на транспортном уровне сети.</p>
<p>Это может усложнить ситуацию, поскольку вы не знаете, каковы ограничения по размеру для различных пользовательских агентов и как они реагируют на отправку или получение сообщения большего размера. Даже когда пользовательские агенты совместно используют одну и ту же базовую библиотеку для обработки данных протокола управления потоком (SCTP), могут существовать различия в зависимости от того, как используется библиотека. Например, и Firefox, и Google Chrome используют библиотеку <code>usrsctp</code> для реализации SCTP, но все ещё существуют ситуации, в которых передача данных по <code>RTCDataChannel</code> каналу может завершиться сбоем из-за различий в том, как они вызывают библиотеку и обрабатывают ошибки, которые она возвращает.</p>
<p>Когда два пользователя, использующие Firefox, обмениваются данными по каналу данных, ограничение размера сообщения намного больше, чем когда Firefox и Chrome обмениваются данными, потому что Firefox реализует устаревшую технику для отправки больших сообщений в нескольких сообщениях SCTP, чего нет в Chrome. Вместо этого Chrome увидит серию сообщений, которые он считает завершёнными, и доставит их получающему <code>RTCDataChannel</code> каналу в виде нескольких сообщений</p>
<p>Сообщения размером менее 16 КБ могут отправляться без проблем, поскольку все основные пользовательские агенты обрабатывают их одинаково.</p>
<h3 id="Проблемы_с_большими_сообщениями">Проблемы с большими сообщениями</h3>
<p>В настоящее время нецелесообразно использовать <code>RTCDataChannel </code>для сообщений размером более 64 КБ (16 КБ, если вы хотите поддерживать кросс-браузерный обмен данными). Проблема возникает из-за того факта, что SCTP - протокол, используемый для отправки и получения данных по <code>RTCDataChannel</code> - изначально был разработан для использования в качестве протокола сигнализации. Ожидалось, что сообщения будут относительно небольшими. Поддержка сообщений, превышающих размер сетевого уровня {{interwiki ("wikipedia", "Maximum unit unit", "MTU")}}, была добавлена в качестве запоздалой мысли, в случае, если сигнальные сообщения должны были быть больше, чем MTU. Эта функция требует, чтобы каждый фрагмент сообщения имел последовательные порядковые номера, поэтому они должны передаваться один за другим, без каких-либо других данных, чередующихся между ними.</p>
<p>В конечном итоге это стало проблемой. Со временем различные приложения (в том числе внедряющие WebRTC) начали использовать SCTP для передачи больших и больших сообщений. В конце концов стало ясно, что когда сообщения становятся слишком большими, передача большого сообщения может блокировать все другие передачи данных в этом канале данных, включая критические сообщения сигнализации.</p>
<p>Это станет проблемой, когда браузеры будут должным образом поддерживать текущий стандарт поддержки больших сообщений - флаг конца записи (EOR), который указывает, когда сообщение является последним в серии, которое следует рассматривать как одну полезную нагрузку. Это реализовано в Firefox 57, но ещё не реализовано в Chrome (см. <a href="https://bugs.chromium.org/p/webrtc/issues/detail?id=7774">Chromium Bug 7774</a>). С поддержкой EOR полезная нагрузка <code>RTCDataChannel</code> может быть намного больше (официально до 256 КБ, но реализация Firefox ограничивает их колоссальным 1 ГБ). Даже при 256 кБ этого достаточно, чтобы вызвать заметные задержки при обработке срочного трафика.</p>
<p>Чтобы решить эту проблему, была разработана новая система планировщиков потоков (обычно называемая «спецификацией данных SCTP»), позволяющая чередовать сообщения, отправленные в разных потоках, включая потоки, используемые для реализации каналов данных WebRTC. Это предложение <a href="https://tools.ietf.org/html/draft-ietf-tsvwg-sctp-ndata">предложение</a> все ещё находится в черновой форме IETF, но после его реализации оно позволит отправлять сообщения практически без ограничений по размеру, поскольку уровень SCTP автоматически чередует лежащие в основе под-сообщения, чтобы обеспечить возможность получения данных каждого канала.</p>
<p>Поддержка Firefox для ndata находится в процессе реализации. <span style="font-size: 1rem; letter-spacing: -0.00278rem;">Команда Chrome отслеживает реализацию поддержки ndata в</span><span style="font-size: 1rem; letter-spacing: -0.00278rem;"> </span><a href="https://bugs.chromium.org/p/webrtc/issues/detail?id=5696" style="font-size: 1rem; letter-spacing: -0.00278rem;">Chrome Bug 5696</a><span style="font-size: 1rem; letter-spacing: -0.00278rem;">.</span></p>
<div class="originaldocinfo">
<p>Большая часть информации в этом разделе частично основана на блоге <a href="https://lgrahl.de/articles/demystifying-webrtc-dc-size-limit.html">Demystifyijng WebRTC's Data Channel Message Size Limitations</a>, написанный Леннартом Гралем. Там он немного подробнее рассказывает, но поскольку браузеры были обновлены с тех пор, некоторые посты могут быть устаревшими. Кроме того, со временем поддержки будет становиться все больше, особенно после того, как EOR и поддержка ndata будут полностью интегрированы в основные браузеры.</p>
</div>
<h2 id="Безопасность">Безопасность</h2>
<p>Все данные, переданные с помощью WebRTC, зашифрованы на основе <a href="/en-US/docs/Web/Security/Transport_Layer_Security">Transport Layer Security</a> (TLS). Поскольку TLS используется для защиты каждого HTTPS-соединения, любые данные, которые вы отправляете по каналу данных, так же безопасны, как и любые другие данные, отправляемые или получаемые браузером пользователя. </p>
<p>Поскольку WebRTC является одноранговым соединением между двумя пользовательскими агентами, данные никогда не проходят через веб-сервер или сервер приложений, что снижает возможность перехвата данных.</p>
|