通过 websocket 接收图片

Posted

技术标签:

【中文标题】通过 websocket 接收图片【英文标题】:Receiving image through websocket 【发布时间】:2012-02-15 11:03:00 【问题描述】:

我正在使用websockify 将图像从 python 服务器显示到 html5 画布。

我认为我已经成功地从我的 python 服务器发送图像,但我无法将图像显示到我的画布上。

我认为问题与我试图在画布上显示的字节数有关,我相信我不会等到收到整个图像后再将图像显示到画布上。

到目前为止,我有:

on 消息功能。当我发送图像时,我在控制台中得到 12 MESSAGERECEIVED

  ws.on('message', function () 
    //console.log("MESSAGERECEIVED!")
            msg(ws.rQshiftStr());
  );

我收到字符串并尝试在画布上显示它的 msg 函数。我为每张图片调用该方法 12 次。刺痛的格式是'xÙõKþ°pãüCY

function msg(str) 
        //console.log(str);
        console.log("RELOAD");

        var ctx = cv.getContext('2d');
        var img = new Image();
        //console.log(str);
        img.src = "data:image/png;base64," + str;
        img.onload = function () 
            ctx.drawImage(img,0,0);
        
    

关于如何解决此问题的任何建议?

【问题讨论】:

除非客户端不支持 hybi 草稿,否则不应通过 websockets 以 base64 格式传输图像。 Base64 将产生 33% 的开销。因此,最好以二进制形式发送。 我认为 websockify 正在将通过它传输的所有内容转换为 base64。 如果是这样,那就太可怕了。寻找另一个 websocket 实现。 @einaros,我在下面的回答中更全面地介绍了 base64 编码/解码,但总而言之,websockify 的重点是在大多数浏览器(不仅仅是现代浏览器)中透明地启用二进制数据.顺便说一句,github.com/einaros/ws 做得很好。我计划在不久的将来更新我的 websockify 节点实现(主要是 python,但我还有其他几个示例实现)以使用您的 lib。 【参考方案1】:

websockify+websock.js 的重点是透明地支持流式二进制数据(更多内容见下文)。您从接收队列中获得的数据已经经过 base64 解码。但是,数据 URI 方案需要一个 base64 编码的字符串,因此您需要将图像数据编码为 base64。您可以使用内置的 window.btoa() 对二进制编码字符串进行 base64 编码:

img.src = "data:image/png;base64," + window.btoa(str);

或者,为了提高效率,您可以使用 include/base64.js 中的 Base64 模块,但您需要将一个字节数组传递给它,就像您从 rQshiftBytes 获得的一样:

msg(ws.rQshiftBytes());

img.src = "data:image/png;base64," + Base64.encode(data);  // str -> data

关于base64在websockify中的使用:

Websockify 使用 base64 对数据进行编码以支持不直接支持二进制数据的浏览器。除了诸如 ios Safari 和桌面 Safari 等流行的仅 Hixie 浏览器外,一些流行的浏览器版本使用 HyBi,但缺少二进制支持。不幸的是,在 Chrome 的情况下,他们大约在同一时间也有一个 WebIDL 错误,这会阻止在建立连接之前检测二进制支持。

此外,在 Opera、firefox 3.6-5、IE 8 和 9 上使用 WebSockets 的主要选项是web-socket-js。 web-socket-js 支持 HyBi,但不支持二进制,并且可能不会,因为它所针对的大多数旧浏览器不支持本机二进制类型(Blob 和类型化数组)。

目前支持 HyBi 和二进制数据的浏览器的市场份额相当低。然而,在未来,Websockify 将检测(通过对象检测或浏览器版本检测)浏览器是否支持二进制数据并直接使用该支持,而不需要 base64 编码/解码。

base64 编码/解码的延迟(和 CPU)开销非常低,并且通常会被网络延迟所抵消。 base64 编码数据的带宽开销约为 25%(即原始数据变大了 33%),但它确实在基本上所有浏览器上通过 WebSockets 为您提供二进制数据(使用 web-socket-js polyfill/shim,即如果需要,websockify 会透明地使用)。

【讨论】:

再次感谢详细的结果。您能否举例说明如何确定图像是否已完全转移?更具体地说,在 python 中,我使用缓冲区大小为 1024 的常规套接字发送数据。如果我有一个大于缓冲区的图像,那么它将以 1024 的部分发送。在浏览器中,这将触发 12 次(如果我有12kb 的图像)websocket 消息事件。如何结合所有这些消息来重建图像?再次感谢。 WebSocketServer.send_frames(bufs) 获取“缓冲区”列表。每个缓冲区将作为单个消息(onmessage 的一次触发)传递给客户端(浏览器)。如果您在 onmessage 中从接收队列中转移所有内容,那么您将收到整个消息。如果您使用较小的块调用 send_frames(或完全绕过 send_frames),那么您将需要在协议中添加一些用于重新构建消息的机制(即在每个消息/图像之前添加长度前缀)。但这是重复的 WebSocket 功能,所以我建议将 send_frames 与整个消息/图像一起使用。 不幸的是,我无法理解如何做到这一点。目前我有一个 python 服务器在Server 1 上发送图像,我有websockifyServer 2 上运行。当我收到消息时,我试图做var arr = ws.rQshiftBytes(ws.rQlen()), str="", chr; while (arr.length > 0) chr = arr.shift(); str += String.fromCharCode(chr); //console.log(str); msg(str); 不幸的是。 ws.on('message', function () 为从服务器发送的每个缓冲区调用,因此我无法确定图片何时准备好以便在画布上绘制它。 啊,我以为您将 websockify 中的 websocket.py 合并为您的 python 服务器的一部分。当您将 websockify 作为 WebSocket 到 TCP 的桥接运行时,您会遇到流/分段(只是 TCP 的本质),因此您必须自己在两个端点之间进行帧/消息处理。您可以将 websocket.py 合并到您的 python 服务器中并直接使用 send_frames,或者将框架添加到您的“协议”中。如果您发送的唯一内容是 PNG 图像,则可以解析出长度。否则,您必须从 python 服务器添加自己的框架。 既然这正在成为一个对话,也许你会考虑向 websockify 提交一个问题以继续在那里?

以上是关于通过 websocket 接收图片的主要内容,如果未能解决你的问题,请参考以下文章

vue+elementUI+WebSocket接收后台实时消息推送

Android websock 应用

websock第一次连不上window

允许在 websockets 中删除消息

015_NGINX作为WebSocket Proxy的设置

初识Websocket