在看代码之前,我们应当首先知道流数据与webSocket 之间的区别(两者不能同一而论),因为存在区别所以在读取数据时使用相对较大的差距
下面我将概述我对两者区别的一个总结(若有不对,请斧正)
流数据(Streaming Data)和 WebSocket 是两种不同的技术,但它们在实时数据传输方面有一些相似之处。以下是它们的区别和相同点:
相同点
1. 实时性 - 两者都支持实时数据传输,适合需要低延迟的场景,如聊天应用、实时监控等。
2. 双向通信 - WebSocket 和某些流数据技术(如 HTTP/2 流)都支持双向通信,客户端和服务器可以同时发送和接收数据。
3. 持续连接 - 两者都通过建立持久连接来传输数据,避免了传统 HTTP 请求的频繁连接和断开。
4. 适合大流量数据 - 两者都适合处理大流量或持续不断的数据流,如视频流、传感器数据等。
区别
特性:
协议:
1,WebSocket 基于 WebSocket 协议(独立的协议,建立在 TCP 之上)
2,流数据(Streaming Data)通常基于 HTTP/1.1 分块传输编码(Chunked Transfer Encoding)或 HTTP/2 流。
通信模式:
1,WebSocket 全双工通信,客户端和服务器可以同时发送和接收数据。
2,流数据(Streaming Data)通常是单向的(如服务器向客户端推送数据),但 HTTP/2 支持双向流。
连接建立:
1,WebSocket 需要握手(Handshake)过程,建立 WebSocket 连接后保持长 连 接
2,流数据(Streaming Data)基于 HTTP 协议,无需额外握手,但可能需要特定 的流传输机制。
数据格式:
1,WebSocket 支持二进制和文本数据格式。
2,流数据(Streaming Data)通常以分块形式传输数据,格式可以是文本、二进 制或其他自定义格式。
应用场景:
1,WebSocket 实时聊天、在线游戏、协作编辑等需要双向通信的场景。
2,流数据(Streaming Data) 视频流、音频流、日志流、传感器数据等单向或双 向数据流场景。
兼容性:
1,WebSocket 需要浏览器和服务器都支持 WebSocket 协议。
2,流数据(Streaming Data)基于 HTTP,兼容性更好,几乎所有浏览器和服务 器都支持
性能:
1, WebSocket 由于是专用协议,性能较高,延迟更低
2,流数据(Streaming Data)性能依赖于 HTTP 协议,可能不如 WebSocket 高 效
接下来我将会先介绍 文本流数据 的读取
流数据,通过 http 协议进行通信 就按照 正常的请求去获取数据
eg:
const response = await fetch('您的URL', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
// 获取响应体的读取器 reader,用于逐块读取流数据。(使用 response.body.getReader()
获取一个 ReadableStreamDefaultReader
实例)
const reader = response.body.getReader();
// 创建一个 TextDecoder
实例,用于将二进制数据解码为 UTF-8 格式的文本。
const decoder = new TextDecoder('utf-8');
let result = ''; // 用于后续存储最后处理的结果
while (true) { // 使用 while(ture) 循环逐快读取流数据
const { done, value } = await reader.read(); // 每次 调用 reader.read(); 返回一个对象(我是进行了解构)
解构参数说明:
done
:表示流是否已经结束(true
表示结束)
value
:当前读取的数据块(二进制数据)。
if (done) break; // 如果 done
为 true
,跳出循环,表示流数据读取完毕。就break 结束循环
// 解码当前块的数据为文本,并将其按行分割
const chunk = decoder.decode(value, { stream: true }); // 使用 TextDecoder
将二进制数据块解码为 UTF-8 格式的文本 const decoder = new TextDecoder('utf-8');
{ stream: true }
表示数据可能是不完整的,后续还会有更多数据块。此时 chunk 就能进行 分割,去空白符等操作(这里我不给实例是因为每个后端可以定义的格式不一样,容易误导)
}
那么触类旁通关于音频流和视频流的相关处理也如上方式,我将分别给出一个实例
1 音频流
async function processAudioStream(url) {
try {
// 发起网络请求获取音频流
const response = await fetch(url);
// 获取响应体的读取器,用于逐块读取音频数据
const reader = response.body.getReader();
// 创建 AudioContext 实例,用于解码和播放音频
const audioContext = new AudioContext();
// 使用 while 循环逐块读取音频数据
while (true) {
// 读取一块数据,返回一个对象 { done, value }
const { done, value } = await reader.read();
// 如果流数据读取完成,跳出循环
if (done) break;
// 解码音频数据为 AudioBuffer
const audioBuffer = await audioContext.decodeAudioData(value.buffer);
// 创建音频源节点
const source = audioContext.createBufferSource();
// 将解码后的音频数据赋值给音频源节点
source.buffer = audioBuffer;
// 将音频源节点连接到音频上下文的目标节点(通常是扬声器) source.connect(audioContext.destination);
// 开始播放音频
source.start();
}
}
catch (error)
{ // 捕获并处理错误 console.error('Error processing audio stream:', error); } }
2 视频流 (使用MediaSource API将视频数据附加到
async function processVideoStream(url) {
try {
// 发起网络请求获取视频流
const response = await fetch(url);
// 获取响应体的读取器,用于逐块读取视频数据
const reader = response.body.getReader();
// 创建 MediaSource 实例,用于处理视频流
const mediaSource = new MediaSource();
// 获取页面中的 video 元素(请使用对应框架的方式来获取DOM元素,我这里是为了方便理解,不推荐)
const video = document.querySelector('video');
// 将 MediaSource 的 URL 赋值给 video 元素的 src
video.src = URL.createObjectURL(mediaSource);
// 监听 MediaSource 的 sourceopen 事件,表示可以开始添加视频数据 mediaSource.addEventListener('sourceopen', () => {
// 创建 SourceBuffer,用于存储视频数据
const sourceBuffer = mediaSource.addSourceBuffer('video/mp4; codecs="avc1.64001e, mp4a.40.2"');
// 定义递归函数,逐块读取并添加视频数据
const appendChunk = async () => {
// 读取一块数据,返回一个对象 { done, value }
const { done, value } = await reader.read();
// 如果流数据读取完成,结束流并返回
if (done) { mediaSource.endOfStream(); return; }
// 将读取的视频数据块添加到 SourceBuffer
sourceBuffer.appendBuffer(value);
// 递归调用,继续读取下一块数据
appendChunk(); };
// 开始读取并添加视频数据
appendChunk();
});
}
catch (error)
{ // 捕获并处理错误 console.error('Error processing video stream:', error); } }
(请多多支持呀~)