Gửi dữ liệu giữa các trình duyệt bằng kênh dữ liệu WebRTC

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 quy trình phức tạp. Phương pháp này yêu cầu thiết lập và trả tiền cho một máy chủ để chuyển tiếp dữ liệu và có thể sẽ mở rộng quy mô này sang nhiều trung tâm dữ liệu. Trong trường hợp này, có thể có độ trễ cao và rất khó để giữ dữ liệu ở chế độ riêng tư.

Những vấn đề này có thể được khắc phục bằng cách sử dụng API RTCDataChannel của WebRTC để truyền dữ liệu trực tiếp từ ứng dụng ngang hàng này sang ứng dụng ngang hàng khác. Bài viết này trình bày những thông tin 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 nên chọn kênh dữ liệu khác?

Chúng tôi có WebSocket, AJAXSự kiện gửi từ máy chủ. Tại sao chúng tôi cần một kênh liên lạc khác? WebSocket hai chiều, nhưng tất cả các công nghệ này được thiết kế để giao tiếp với hoặc từ máy chủ.

RTCDataChannel có một phương pháp khác:

  • Thư viện 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ể dẫn đến thời gian chờ thấp hơn – không có máy chủ trung gian và ít 'bước'.
  • RTCDataChannel sử dụng Giao thức truyền điều khiển luồng (SCTP), cho phép cấu hình truyền tải và phân phối ngữ nghĩa phân phối không theo thứ tự có thể định cấu hình.

RTCDataChannel hiện được cung cấp cùng với dịch vụ hỗ trợ SCTP trên máy tính và Android trong Google Chrome, Opera và Firefox.

Cảnh báo: Tín hiệu, STUN và TURN

WebRTC cho phép giao tiếp ngang hàng nhưng vẫn cần máy chủ dùng để gửi tín 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 đối phó với 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 ứng dụng ngang hàng.
  • Máy chủ STUN để xác định IP và cổng có thể truy cập công khai cho mỗi ứng dụng ngang hàng.
  • TURN máy chủ nếu không kết nối trực tiếp được 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 máy chủ để truyền tín hiệu và kết nối mạng, hãy xem phần WebRTC trong thế giới thực: STUN, TURN và báo hiệu.

Khả năng

API RTCDataChannel hỗ trợ một tập hợp các loại dữ liệu linh hoạt. API được thiết kế để bắt chước 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, ArrayBufferArrayBufferView. Các kiểu này có thể hữu ích khi 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ự với Giao thức Datagram của người dùng hoặc UDP), chế độ đáng tin cậy và có thứ tự (tương tự với Giao thức điều khiển truyền dẫn hoặc TCP) và các chế độ đáng 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ự gửi tin nhắn. Việc này sẽ làm tiêu tốn thêm tài nguyên, 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ư đều được chuyển tới phía bên kia cũng như thứ tự chuyển thư. Việc này loại bỏ chi phí chung, 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 tin nhắn trong một điều kiện cụ thể, chẳng hạn như hết thời gian chờ truyền lại hoặc lượng nội dung truyền lại tối đa. Bạn cũng có thể định cấu hình thứ tự của tin nhắn.

Hiệu suất của 2 chế độ đầu tiên là như nhau khi không có tình trạng mất gói dữ liệu. Tuy nhiên, ở chế độ đáng tin cậy và có thứ tự, một gói bị mất khiến các gói khác bị chặn phía sau nó 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. 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 từ bài viết Mạng lưới trình duyệt hiệu suất cao của Ilya Grigorik:

TCPUDPSCTP
Độ tin cậyĐáng tin cậyKhông đáng tin cậyCó thể định cấu hình
Giao hàngĐã đặt mónKhông theo thứ tựCó thể định cấu hình
Truyền dữ liệuHướng byteHướng thông báoHướng thông báo
Điều khiển luồngKhông
Kiểm soát tắc nghẽnKhông

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 chế độ không đáng tin cậy và không theo 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 kết nối ngang hàng với chính mình, sau đó tạo kênh dữ liệu và gửi thông báo thông qua kết nối ngang hàng. Sau đó, Google sẽ tạo một kênh dữ liệu và gửi thông báo bằng kết nối ngang hàng. Cuối cùng, thư của bạn sẽ xuất hiện trong hộp ở phía bên kia của trang!

Mã để bắt đầu thực hiện việc 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 đã thiết lập. Bạn có thể tạo tín hiệu trước hoặc sau khi gửi tín hiệu. Sau đó, bạn chuyển vào một nhãn để phân biệt kênh này với các kênh khác, cùng với một nhóm 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 thất bại), 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 0ordered thành false. Để biết thêm thông tin, hãy xem các RFC sau của IETF: Giao thức truyền điều khiển luồngPhần mở rộng về độ tin cậy một phần của giao thức điều khiển luồng.

  • ordered: kênh dữ liệu có đảm bảo đơn đặt hàng hay không
  • maxPacketLifeTime: thời gian tối đa để thử và truyền lại một tin nhắn không thành công
  • maxRetransmits: số lần tối đa để thử và truyền lại một tin nhắn không thành công
  • protocol: cho phép sử dụng một giao thức phụ, giao thức này cung cấp thông tin meta về ứng dụng
  • negotiated: 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 một kênh dữ liệu ở ứng dụng ngang hàng khác, nhờ đó bạn có thể tạo kênh dữ liệu có cùng mã nhận dạng ở phía bên kia
  • id: cho phép bạn cung cấp mã nhận dạng riêng cho kênh. Mã này chỉ có thể sử dụng kết hợp với negotiated được đặt thành true)

3 lựa chọn duy nhất mà hầu hết mọi người cần sử dụng là 3 lựa chọn đầu tiên: ordered, maxPacketLifeTimemaxRetransmits. Với SCTP (hiện được tất cả trình duyệt hỗ trợ WebRTC) đáng tin cậy và được sắp xếp theo mặc định. Nên sử dụng phương pháp không đáng tin cậy và không có thứ tự nếu bạn 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, chỉ số tin cậy một phần là rất hữu ích.

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ừ ứng dụng ngang hàng khác.

Thử thách này có an toàn không?

Tất cả thành phần WebRTC đều bắt buộc phải có quy trình mã hóa. Với RTCDataChannel, mọi dữ liệu đều được bảo mật bằng Bảo mật tầng truyền tải gói dữ liệu (DTLS). DTLS là phiên bản phái sinh của SSL, nghĩa là dữ liệu của bạn sẽ được bảo mật như sử dụng bất kỳ kết nối chuẩn dựa trên SSL nào. DTLS được chuẩn hoá và tích hợp vào tất cả các trình duyệt hỗ trợ WebRTC. Để biết thêm thông tin, hãy xem Wireshark wiki.

Thay đổi cách suy nghĩ về dữ liệu

Việc xử lý một lượng lớn dữ liệu có thể là một vấn đề trong JavaScript. Như các nhà phát triển của Sharefest đã chỉ ra, điều này đòi hỏi phải suy nghĩ về dữ liệu theo một cách mới. Nếu chuyển tệp lớn hơn dung lượng bộ nhớ hiện có, bạn phải nghĩ đến 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 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 xây dựng trên RTCDataChannel có nghĩa là dữ liệu tệp được chuyển sẽ được mã hoá và không chạm vào 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 việc chia sẻ tệp WebRTC trở thành một ứng cử viên sáng giá cho web.

Bạn cần thực hiện một số bước để chuyển khoản thành công:

  1. Đọc một tệp trong JavaScript bằng File API.
  2. Tạo kết nối ngang hàng giữa các ứng dụng bằng RTCPeerConnection.
  3. Tạo kênh dữ liệu giữa các ứng dụng bằng RTCDataChannel.

Có một số điểm cần cân nhắc khi cố gắng gửi các 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ữ cũng như tải dưới dạng một Blob, bạn có thể tải vào bộ nhớ bằng API Tệp, 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 truyền tối đa). Khi kích thước tệp ngày 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 tệp sẽ được tải và gửi cho một ứng dụng ngang hàng khác, đi kèm với siêu dữ liệu chunkID để ứng dụng ngang hàng có thể nhận ra các phần đó. 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 API FileSystem) 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à những "nguyên tử" nhỏ nhất của dữ liệu cho ứng dụng của bạn. Bạn cần phân đoạn dữ liệu vì hiện tại chúng tôi đã có giới hạn về kích thước khi 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 sau này). Đề xuất hiện tại cho kích thước phân đoạn tối đa là 64 KB.

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 cách sử dụng thẻ ký tự liên kết:

function saveFile(blob) {
  const link = document.createElement('a');
  link.href = window.URL.createObjectURL(blob);
  link.download = 'File Name';
  link.click();
};

Các ứng dụng chia sẻ tệp này trên PubShareGitHub 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 một ứ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 thức mới để xây dựng ứng dụng nhằm chia sẻ tệp, chơi trò chơi nhiều người chơi và phân phối nội dung.

  • Chia sẻ tệp ngang hàng như mô tả trước đó
  • Trò chơi nhiều người chơi, được ghép nối 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 đang được PeerCDN cải tiến, một khung phân phối tài sản web thông qua hoạt động 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 hiệu suất cao với độ trễ thấp thông qua RTCDataChannel. Các khung (chẳng hạn như PeerJSSDK 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 nhiều nền tảng.

Sự ra đời 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.

Tìm hiểu thêm