WebTransport 提供了发送udp ,tcp的功能
列子:
- 一、数据包发送接收
1.发送数据包消息
async function sendDatagrams(url, datagrams) {
const wt = new WebTransport(url);
const writer = wt.datagrams.writable.getWriter();
for (const datagram of datagrams) {
await writer.ready;
writer.write(datagram).catch(() => {});
}
}
2.定时发送数据包
async function sendFixedRate(url, createDatagram, ms = 100) {
const wt = new WebTransport(url);
await wt.ready;
const writer = wt.datagrams.writable.getWriter();
const datagram = createDatagram();
setInterval(() => writer.write(datagram).catch(() => {}), ms);
}
3.接收数据包
async function receiveDatagrams(url) {
const wt = new WebTransport(url);
for await (const datagram of wt.datagrams.readable) {
// Process the datagram
}
}
- 二、数据流发送接收
1.发送数据流
async function sendData(url, data) {
const wt = new WebTransport(url);
const writable = await wt.createUnidirectionalStream();
const writer = writable.getWriter();
await writer.write(data);
await writer.close();
}
2.发送文字消息
async function sendText(url, readableStreamOfTextData) {
const wt = new WebTransport(url);
const writable = await wt.createUnidirectionalStream();
await readableStreamOfTextData
.pipeThrough(new TextEncoderStream("utf-8"))
.pipeTo(writable);
}
3.接收数据流
async function receiveData(url, processTheData) {
const wt = new WebTransport(url);
for await (const readable of wt.incomingUnidirectionalStreams) {
// consume streams individually, reporting per-stream errors
((async () => {
try {
for await (const chunk of readable.getReader()) {
processTheData(chunk);
}
} catch (e) {
console.error(e);
}
})());
}
}
4.接收文字消息
async function receiveText(url, createWritableStreamForTextData) {
const wt = new WebTransport(url);
for await (const readable of wt.incomingUnidirectionalStreams) {
// consume sequentially to not interleave output, reporting per-stream errors
try {
await readable
.pipeThrough(new TextDecoderStream("utf-8"))
.pipeTo(createWritableStreamForTextData());
} catch (e) {
console.error(e);
}
}
}
- 三、简单的完整例子
let wt, streamNumber, datagramWriter;
connect.onclick = async () => {
try {
const url = document.getElementById('url').value;
wt = new WebTransport(url);
addToEventLog('Initiating connection...');
await wt.ready;
addToEventLog('Connection ready.');
wt.closed
.then(() => addToEventLog('Connection closed normally.'))
.catch(() => addToEventLog('Connection closed abruptly.', 'error'));
streamNumber = 1;
datagramWriter = wt.datagrams.writable.getWriter();
readDatagrams();
acceptUnidirectionalStreams();
document.forms.sending.elements.send.disabled = false;
document.getElementById('connect').disabled = true;
} catch (e) {
addToEventLog(`Connection failed. ${e}`, 'error');
}
}
sendData.onclick = async () => {
const form = document.forms.sending.elements;
const rawData = sending.data.value;
const data = new TextEncoder('utf-8').encode(rawData);
try {
switch (form.sendtype.value) {
case 'datagram': {
await datagramWriter.write(data);
addToEventLog(`Sent datagram: ${rawData}`);
break;
}
case 'unidi': {
const writable = await wt.createUnidirectionalStream();
const writer = writable.getWriter();
await writer.write(data);
await writer.close();
addToEventLog(`Sent a unidirectional stream with data: ${rawData}`);
break;
}
case 'bidi': {
const duplexStream = await wt.createBidirectionalStream();
const n = streamNumber++;
readFromIncomingStream(duplexStream.readable, n);
const writer = duplexStream.writable.getWriter();
await writer.write(data);
await writer.close();
addToEventLog(`Sent bidirectional stream #${n} with data: ${rawData}`);
break;
}
}
} catch (e) {
addToEventLog(`Error while sending data: ${e}`, 'error');
}
}
// Reads datagrams into the event log until EOF is reached.
async function readDatagrams() {
try {
const decoder = new TextDecoderStream('utf-8');
for await (const data of wt.datagrams.readable.pipeThrough(decoder)) {
addToEventLog(`Datagram received: ${data}`);
}
addToEventLog('Done reading datagrams!');
} catch (e) {
addToEventLog(`Error while reading datagrams: ${e}`, 'error');
}
}
async function acceptUnidirectionalStreams() {
try {
for await (const readable of wt.incomingUnidirectionalStreams) {
const number = streamNumber++;
addToEventLog(`New incoming unidirectional stream #${number}`);
readFromIncomingStream(readable, number);
}
addToEventLog('Done accepting unidirectional streams!');
} catch (e) {
addToEventLog(`Error while accepting streams ${e}`, 'error');
}
}
async function readFromIncomingStream(readable, number) {
try {
const decoder = new TextDecoderStream('utf-8');
for await (const chunk of readable.pipeThrough(decoder)) {
addToEventLog(`Received data on stream #${number}: ${chunk}`);
}
addToEventLog(`Stream #${number} closed`);
} catch (e) {
addToEventLog(`Error while reading from stream #${number"}: ${e}`, 'error');
addToEventLog(` ${e.message}`);
}
}
function addToEventLog(text, severity = 'info') {
const log = document.getElementById('event-log');
const previous = log.lastElementChild;
const entry = document.createElement('li');
entry.innerText = text;
entry.className = `log-${severity}`;
log.appendChild(entry);
// If the previous entry in the log was visible, scroll to the new element.
if (previous &&
previous.getBoundingClientRect().top < log.getBoundingClientRect().bottom) {
entry.scrollIntoView();
}
}