web 使用udp 进行数据通信

原创
2022/01/14 20:03
阅读数 1.5K

 

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();
  }
}

 

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部