Việc gửi dữ liệu giữa hai trình duyệt để giao tiếp, chơi trò chơi hoặc chuyển tệp có thể là một quá trình khá phức tạp. Bạn cần thiết lập và trả phí cho một máy chủ để chuyển tiếp dữ liệu, đồng thời có thể mở rộng quy mô cho nhiều trung tâm dữ liệu. Trong trường hợp này, có thể xảy ra độ trễ cao và khó giữ bí mật dữ liệu.
Bạn có thể giảm thiểu các vấn đề này bằng cách sử dụng API RTCDataChannel
của WebRTC để truyền dữ liệu trực tiếp từ máy khách này sang máy khách khác. Bài viết này trình bày các kiến thức cơ bản về cách thiết lập và sử dụng kênh dữ liệu, cũng như các trường hợp sử dụng phổ biến trên web hiện nay.
Tại sao có kênh dữ liệu khác?
Chúng ta có WebSocket, AJAX và Sự kiện do máy chủ gửi. Tại sao chúng ta cần một kênh liên lạc khác? WebSocket là hai chiều, nhưng tất cả các công nghệ này đều được thiết kế để giao tiếp với hoặc từ máy chủ.
RTCDataChannel
sử dụng một phương pháp khác:
- API này hoạt động với API
RTCPeerConnection
, cho phép kết nối ngang hàng. Điều này có thể làm giảm độ trễ – không có máy chủ trung gian và ít "đường truyền" hơn. RTCDataChannel
sử dụng Giao thức truyền điều khiển luồng (SCTP), cho phép cấu hình phân phối ngữ nghĩa-phân phối không theo thứ tự và cấu hình truyền lại.
RTCDataChannel
hiện có hỗ trợ SCTP trên máy tính và Android trong Google Chrome, Opera và Firefox.
Cảnh báo: Báo hiệu, STUN và TURN
WebRTC cho phép giao tiếp ngang hàng, nhưng vẫn cần máy chủ để báo hiệu trao đổi siêu dữ liệu mạng và nội dung nghe nhìn nhằm khởi động kết nối ngang hàng.
WebRTC xử lý các NAT và tường lửa với:
- Khung ICE để thiết lập đường dẫn mạng tốt nhất có thể giữa các máy ngang hàng.
- Máy chủ STUN để xác định một địa chỉ IP và cổng có thể truy cập công khai cho mỗi máy ngang hàng.
- Máy chủ TURN nếu không kết nối được trực tiếp và cần chuyển tiếp dữ liệu.
Để biết thêm thông tin về cách WebRTC hoạt động với các máy chủ để báo hiệu và kết nối mạng, hãy xem bài viết WebRTC trong thực tế: STUN, TURN và báo hiệu.
Các chức năng
API RTCDataChannel
hỗ trợ một tập hợp các loại dữ liệu linh hoạt. API này được thiết kế để mô phỏng chính xác WebSocket và RTCDataChannel
hỗ trợ chuỗi cũng như một số loại tệp nhị phân trong JavaScript, chẳng hạn như Blob, ArrayBuffer và ArrayBufferView. Các loại này có thể hữu ích khi bạn làm việc với tính năng chuyển tệp và chơi trò chơi nhiều người chơi.
RTCDataChannel
có thể hoạt động ở chế độ không đáng tin cậy và không theo thứ tự (tương tự như Giao thức gói dữ liệu người dùng hoặc UDP), chế độ tin cậy và có thứ tự (tương tự như Giao thức điều khiển truyền hoặc TCP) cũng như chế độ tin cậy một phần:
- Chế độ đáng tin cậy và có thứ tự đảm bảo việc truyền tin nhắn cũng như thứ tự phân phối tin nhắn. Điều này sẽ làm tốn thêm chi phí, do đó có thể làm cho chế độ này chậm hơn.
- Chế độ không đáng tin cậy và không theo thứ tự không đảm bảo mọi thông báo đều được gửi đến bên kia cũng như thứ tự gửi thông báo. Điều này giúp loại bỏ hao tổn, cho phép chế độ này hoạt động nhanh hơn nhiều.
- Chế độ đáng tin cậy một phần đảm bảo việc truyền thông báo trong một điều kiện cụ thể, chẳng hạn như thời gian chờ truyền lại hoặc số lần truyền lại tối đa. Bạn cũng có thể định cấu hình thứ tự của các thông báo.
Hiệu suất của hai chế độ đầu tiên gần như giống nhau khi không có gói dữ liệu nào bị mất. Tuy nhiên, ở chế độ đáng tin cậy và có thứ tự, một gói bị mất sẽ khiến các gói khác bị chặn phía sau gói đó và gói bị mất có thể đã lỗi thời vào thời điểm được truyền lại và đến nơi. Tất nhiên, bạn có thể sử dụng nhiều kênh dữ liệu trong cùng một ứng dụng, mỗi kênh có ngữ nghĩa riêng đáng tin cậy hoặc không đáng tin cậy.
Dưới đây là bảng hữu ích trong bài viết High Performance Browser Networking (Mạng truyền tải trình duyệt hiệu suất cao) của Ilya Grigorik:
TCP | UDP | SCTP | |
Độ tin cậy | Đáng tin cậy | Không đáng tin cậy | Có thể định cấu hình |
Giao hàng | Đã đặt hàng | Không theo thứ tự | Có thể định cấu hình |
Hệ thống truyền động | Theo hướng byte | Định hướng theo thông điệp | Định hướng theo thông điệp |
Kiểm soát luồng | Có | Không | Có |
Kiểm soát tình trạng tắc nghẽn | Có | Không | Có |
Tiếp theo, bạn sẽ tìm hiểu cách định cấu hình RTCDataChannel
để sử dụng chế độ đáng tin cậy và có thứ tự hoặc không đáng tin cậy và không có thứ tự.
Định cấu hình kênh dữ liệu
Có một số bản minh hoạ đơn giản về RTCDataChannel
trực tuyến:
Trong các ví dụ này, trình duyệt tạo một kết nối ngang hàng với chính nó, sau đó tạo một kênh dữ liệu và gửi thông báo thông qua kết nối ngang hàng. Sau đó, ứng dụng này sẽ tạo một kênh dữ liệu và gửi thông báo dọc theo kết nối ngang hàng. Cuối cùng, thông báo của bạn sẽ xuất hiện trong hộp ở phía bên kia của trang!
Mã để bắt đầu với tính năng này rất ngắn:
const peerConnection = new RTCPeerConnection();
// Establish your peer connection using your signaling channel here
const dataChannel =
peerConnection.createDataChannel("myLabel", dataChannelOptions);
dataChannel.onerror = (error) => {
console.log("Data Channel Error:", error);
};
dataChannel.onmessage = (event) => {
console.log("Got Data Channel Message:", event.data);
};
dataChannel.onopen = () => {
dataChannel.send("Hello World!");
};
dataChannel.onclose = () => {
console.log("The Data Channel is Closed");
};
Đối tượng dataChannel
được tạo từ một kết nối ngang hàng đã được thiết lập. Bạn có thể tạo trước hoặc sau khi tín hiệu xảy ra. Sau đó, bạn truyền vào một nhãn để phân biệt kênh này với các kênh khác và một tập hợp các chế độ cài đặt cấu hình không bắt buộc:
const dataChannelOptions = {
ordered: false, // do not guarantee order
maxPacketLifeTime: 3000, // in milliseconds
};
Bạn cũng có thể thêm tuỳ chọn maxRetransmits
(số lần thử trước khi không thành công), nhưng bạn chỉ có thể chỉ định maxRetransmits hoặc maxPacketLifeTime, chứ không được chỉ định cả hai. Đối với ngữ nghĩa UDP, hãy đặt maxRetransmits
thành 0
và ordered
thành false
. Để biết thêm thông tin, hãy xem các RFC IETF sau: Giao thức truyền điều khiển luồng và Phần mở rộng về độ tin cậy một phần của giao thức điều khiển luồng.
ordered
: liệu kênh dữ liệu có đảm bảo thứ tự hay khôngmaxPacketLifeTime
: thời gian tối đa để thử và truyền lại một thông báo không thành côngmaxRetransmits
: số lần tối đa để thử và truyền lại một thông báo không thành côngprotocol
: cho phép sử dụng một giao thức phụ cung cấp thông tin siêu dữ liệu cho ứng dụngnegotiated
: nếu bạn đặt chính sách này thành true, thì hệ thống sẽ xoá chế độ thiết lập tự động cho kênh dữ liệu của các ứng dụng ngang hàng khác, từ đó cung cấp cho bạn cách tạo kênh dữ liệu có cùng mã nhận dạng ở bên kiaid
: cho phép bạn cung cấp mã nhận dạng của riêng mình cho kênh. Mã nhận dạng này chỉ có thể được sử dụng kết hợp vớinegotiated
được đặt thànhtrue
)
Các tuỳ chọn duy nhất mà hầu hết mọi người cần sử dụng là 3 tuỳ chọn đầu tiên: ordered
, maxPacketLifeTime
và maxRetransmits
. Với SCTP (hiện được tất cả trình duyệt hỗ trợ WebRTC sử dụng), đáng tin cậy và có thứ tự là đúng theo mặc định. Bạn nên sử dụng không đáng tin cậy và không theo thứ tự nếu muốn có toàn quyền kiểm soát từ lớp ứng dụng, nhưng trong hầu hết các trường hợp, độ tin cậy một phần sẽ hữu ích.
Xin lưu ý rằng, giống như WebSocket, RTCDataChannel
sẽ kích hoạt các sự kiện khi một kết nối được thiết lập, đóng hoặc gặp lỗi và khi nhận được thông báo từ máy chủ ngang hàng khác.
Thử thách này có an toàn không?
Mã hóa là bắt buộc đối với tất cả các thành phần WebRTC. Với RTCDataChannel
, tất cả dữ liệu đều được bảo mật bằng Bảo mật tầng truyền tải Datagram (DTLS). DTLS là một sản phẩm phái sinh của SSL, nghĩa là dữ liệu của bạn sẽ được bảo mật như khi sử dụng bất kỳ kết nối tiêu chuẩn nào dựa trên SSL. DTLS được chuẩn hoá và tích hợp vào tất cả trình duyệt hỗ trợ WebRTC. Để biết thêm thông tin, hãy xem Wireshark wiki.
Thay đổi cách bạn suy nghĩ về dữ liệu
Việc xử lý lượng lớn dữ liệu có thể là một vấn đề khó khăn trong JavaScript. Như các nhà phát triển của Sharefest đã chỉ ra, để làm được điều này, bạn phải tư duy về dữ liệu theo một cách mới. Nếu đang chuyển một tệp lớn hơn dung lượng bộ nhớ hiện có, bạn phải suy nghĩ về những cách mới để lưu thông tin này. Đây là nơi các công nghệ, chẳng hạn như FileSystem API, phát huy tác dụng, như bạn sẽ thấy trong phần tiếp theo.
Tạo ứng dụng chia sẻ tệp
Giờ đây, bạn có thể tạo một ứng dụng web có thể chia sẻ tệp trong trình duyệt bằng RTCDataChannel
. Được tạo dựa trên RTCDataChannel
có nghĩa là dữ liệu tệp đã chuyển sẽ được mã hoá và không chạm đến máy chủ của nhà cung cấp ứng dụng. Chức năng này, kết hợp với khả năng kết nối với nhiều ứng dụng để chia sẻ nhanh hơn, giúp tính năng chia sẻ tệp WebRTC trở thành một ứng dụng mạnh mẽ cho web.
Bạn cần thực hiện một số bước để chuyển khoản thành công:
- Đọc tệp trong JavaScript bằng File API (API Tệp).
- Tạo kết nối ngang hàng giữa các ứng dụng bằng
RTCPeerConnection
. - Tạo kênh dữ liệu giữa các ứng dụng bằng
RTCDataChannel
.
Có một vài điểm cần cân nhắc khi cố gắng gửi tệp qua RTCDataChannel
:
- Kích thước tệp: nếu kích thước tệp nhỏ hợp lý và có thể được lưu trữ và tải dưới dạng một Blob, thì bạn có thể tải vào bộ nhớ bằng File API, sau đó gửi tệp qua một kênh đáng tin cậy như hiện tại (mặc dù hãy lưu ý rằng trình duyệt áp đặt giới hạn về kích thước chuyển tối đa). Khi kích thước tệp càng lớn, mọi thứ sẽ trở nên phức tạp hơn. Khi cần có cơ chế phân đoạn, các phân đoạn tệp sẽ được tải và gửi đến một máy ngang hàng khác, kèm theo siêu dữ liệu
chunkID
để máy ngang hàng có thể nhận ra các phân đoạn đó. Xin lưu ý rằng trong trường hợp này, trước tiên, bạn cũng cần lưu các đoạn vào bộ nhớ ngoại tuyến (ví dụ: sử dụng FileSystem API) và chỉ lưu vào ổ đĩa của người dùng khi bạn có toàn bộ tệp. - Kích thước phân đoạn: đây là các "nguyên tử" dữ liệu nhỏ nhất cho ứng dụng của bạn. Bạn phải phân đoạn vì hiện có giới hạn kích thước gửi (mặc dù vấn đề này sẽ được khắc phục trong phiên bản kênh dữ liệu trong tương lai). Kích thước khối tối đa được đề xuất hiện tại là 64KiB.
Sau khi tệp được chuyển hoàn toàn sang phía bên kia, bạn có thể tải tệp đó xuống bằng thẻ neo:
function saveFile(blob) {
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = 'File Name';
link.click();
};
Những ứng dụng chia sẻ tệp này trên PubShare và GitHub sử dụng kỹ thuật này. Cả hai đều là nguồn mở và cung cấp nền tảng tốt cho ứng dụng chia sẻ tệp dựa trên RTCDataChannel
.
Vậy bạn có thể làm gì?
RTCDataChannel
mở ra những cách mới để xây dựng ứng dụng chia sẻ tệp, chơi trò chơi nhiều người chơi và phân phối nội dung.
- Hoạt động chia sẻ tệp ngang hàng như mô tả trước đó
- Chơi trò chơi nhiều người chơi, kết hợp với các công nghệ khác, chẳng hạn như WebGL, như trong BananaBread của Mozilla
- Phân phối nội dung được PeerCDN tái tạo, một khung phân phối tài sản web thông qua giao tiếp dữ liệu ngang hàng
Thay đổi cách bạn xây dựng ứng dụng
Giờ đây, bạn có thể cung cấp các ứng dụng hấp dẫn hơn bằng cách sử dụng các kết nối có hiệu suất cao, độ trễ thấp thông qua RTCDataChannel
. Các khung, chẳng hạn như PeerJS và SDK WebRTC PubNub, giúp triển khai RTCDataChannel
dễ dàng hơn và API hiện được hỗ trợ rộng rãi trên các nền tảng.
Sự xuất hiện của RTCDataChannel
có thể thay đổi cách bạn nghĩ về việc chuyển dữ liệu trong trình duyệt.