如何通过 Websocket 发送文件以及其他信息?
How to send File through Websocket along with additional info?
我正在开发一个 Web 应用程序,用于从管理界面向两台显示器发送图像、视频等。我在服务器端使用 Node.js 中的 ws。我已经实现了选择服务器和外部 URL 上可用的图像并将它们发送到客户端,但我还希望能够直接发送从带有文件输入的设备中选择的图像。我设法使用 base64 做到了,但我认为它效率很低。
目前我发送一个字符串化的 JSON 对象,其中包含资源必须发送到的客户端、资源的种类和资源本身,在服务器中解析它并将其发送到适当的客户端。我知道我可以将 Websocket binaryType 设置为 blob 并只发送 File 对象,但是我无法告诉服务器它必须将它发送到哪个客户端。我尝试使用 typeson 和 BSON 来完成此操作,但没有成功。
还有其他方法吗?
您可以通过 WebSocket 发送原始二进制数据。
非常容易管理。
一个选项是在前面添加 "magic byte"(将消息标记为 non-JSON 的标识符)。例如,在二进制消息前加上 B
字符。
服务器所要做的就是在收集二进制数据之前测试第一个字符(如果没有魔术字节,则可能是正常的 JSON 消息)。
更严格的实现会在魔术字节(即文件名、总长度、发送数据的位置等)后附加一个 header。
这允许在断开连接时继续上传(仅发送未确认收到的部分。
您的服务器在处理之前需要将数据拆分为 magic byte
、header
和 binary_data
。但它很容易完成。
希望这对某人有所帮助。
根据 socket.io 文档,您可以发送字符串、缓冲区或两者混合
在客户端:
function uploadFile(e, socket, to) {
let file = e.target.files[0];
if (!file) {
return
}
if (file.size > 10000000) {
alert('File should be smaller than 1MB')
return
}
var reader = new FileReader();
var rawData = new ArrayBuffer();
reader.onload = function (e) {
rawData = e.target.result;
socket.emit("send_message", {
type: 'attachment',
data: rawData
} , (result) => {
alert("Server has received file!")
});
alert("the File has been transferred.")
}
reader.readAsArrayBuffer(file);
}
在服务器端:
socket.on('send_message', async (data, cb) => {
if (data.type == 'attachment') {
console.log('Found binary data')
cb("Received file successfully.")
return
}
// Process other business...
});
我使用的是没有 io 的纯 WebSocket,您不能在其中混合内容 - 字符串或二进制。那么我的工作解决方案是这样的:
客户:
import { serialize } from 'bson';
import { Buffer } from 'buffer';
const reader = new FileReader();
let rawData = new ArrayBuffer();
ws = new WebSocket(...)
reader.onload = (e) => {
rawData = e.target.result;
const bufferData = Buffer.from(rawData);
const bsonData = serialize({ // whatever js Object you need
file: bufferData,
route: 'TRANSFER',
action: 'FILE_UPLOAD',
});
ws.send(bsonData);
}
然后在 Node 服务器端,消息被捕获并像这样解析:
const dataFromClient = deserialize(wsMessage, {promoteBuffers: true}) // edited
fs.writeFile(
path.join('../server', 'yourfiles', 'yourfile.txt'),
dataFromClient.file, // edited
'binary',
(err) => {
console.log('ERROR!!!!', err);
}
);
杀手是反序列化函数中的 promoteBuffer
选项。
我正在开发一个 Web 应用程序,用于从管理界面向两台显示器发送图像、视频等。我在服务器端使用 Node.js 中的 ws。我已经实现了选择服务器和外部 URL 上可用的图像并将它们发送到客户端,但我还希望能够直接发送从带有文件输入的设备中选择的图像。我设法使用 base64 做到了,但我认为它效率很低。
目前我发送一个字符串化的 JSON 对象,其中包含资源必须发送到的客户端、资源的种类和资源本身,在服务器中解析它并将其发送到适当的客户端。我知道我可以将 Websocket binaryType 设置为 blob 并只发送 File 对象,但是我无法告诉服务器它必须将它发送到哪个客户端。我尝试使用 typeson 和 BSON 来完成此操作,但没有成功。
还有其他方法吗?
您可以通过 WebSocket 发送原始二进制数据。
非常容易管理。
一个选项是在前面添加 "magic byte"(将消息标记为 non-JSON 的标识符)。例如,在二进制消息前加上 B
字符。
服务器所要做的就是在收集二进制数据之前测试第一个字符(如果没有魔术字节,则可能是正常的 JSON 消息)。
更严格的实现会在魔术字节(即文件名、总长度、发送数据的位置等)后附加一个 header。
这允许在断开连接时继续上传(仅发送未确认收到的部分。
您的服务器在处理之前需要将数据拆分为 magic byte
、header
和 binary_data
。但它很容易完成。
希望这对某人有所帮助。 根据 socket.io 文档,您可以发送字符串、缓冲区或两者混合
在客户端:
function uploadFile(e, socket, to) {
let file = e.target.files[0];
if (!file) {
return
}
if (file.size > 10000000) {
alert('File should be smaller than 1MB')
return
}
var reader = new FileReader();
var rawData = new ArrayBuffer();
reader.onload = function (e) {
rawData = e.target.result;
socket.emit("send_message", {
type: 'attachment',
data: rawData
} , (result) => {
alert("Server has received file!")
});
alert("the File has been transferred.")
}
reader.readAsArrayBuffer(file);
}
在服务器端:
socket.on('send_message', async (data, cb) => {
if (data.type == 'attachment') {
console.log('Found binary data')
cb("Received file successfully.")
return
}
// Process other business...
});
我使用的是没有 io 的纯 WebSocket,您不能在其中混合内容 - 字符串或二进制。那么我的工作解决方案是这样的:
客户:
import { serialize } from 'bson';
import { Buffer } from 'buffer';
const reader = new FileReader();
let rawData = new ArrayBuffer();
ws = new WebSocket(...)
reader.onload = (e) => {
rawData = e.target.result;
const bufferData = Buffer.from(rawData);
const bsonData = serialize({ // whatever js Object you need
file: bufferData,
route: 'TRANSFER',
action: 'FILE_UPLOAD',
});
ws.send(bsonData);
}
然后在 Node 服务器端,消息被捕获并像这样解析:
const dataFromClient = deserialize(wsMessage, {promoteBuffers: true}) // edited
fs.writeFile(
path.join('../server', 'yourfiles', 'yourfile.txt'),
dataFromClient.file, // edited
'binary',
(err) => {
console.log('ERROR!!!!', err);
}
);
杀手是反序列化函数中的 promoteBuffer
选项。