【问题标题】:Can I Dynamically Update HTML Over a Web Socket?我可以通过 Web 套接字动态更新 HTML 吗?
【发布时间】:2017-06-07 18:57:14
【问题描述】:

我是 Web 套接字的新手,我正在围绕与物联网设备对话的命令行界面构建一个 Web GUI。有些命令需要几秒钟才能运行,因为我将它们发送到大型设备网络。

如果我可以在响应进入时将单个设备响应传递给文本区域(类似于终端窗口),那将非常有帮助。

我在客户端和服务器之间使用 Web 套接字连接。这是我想要达到的效果的简化示例。

#!/usr/bin/env perl

use strict;
use warnings;
use Mojolicious::Lite;

get '/' => 'index';

websocket '/get_loop' => sub {

    my $c = shift;

    $c->app->log->debug("Websocket opened");

    $c->on(message => sub {

        my ($c, $msg) = @_;

        for (my $i = 0; $i < 10; $i++) {
            $c->send("$i\n");
            $c->app->log->debug("$i\n");
            sleep (1);
        };
    });

    $c->on(finish => sub {
        my ($c, $code, $reason) = @_;
        $c->app->log->debug("WebSocket closed with status $code");
    });
};

app->start;

__DATA__

@@ index.html.ep
<html>
<head>
    <title>Websocket Test</title>
    <style type="text/css">
        textarea {
            height: 200px;
            width: 100px;
        }
    </style>
</head>
<body>
    <h1>Websocket Test</h1>
    <textarea id="terminal" readonly></textarea>
    <script type="text/javascript">
        var ws = new WebSocket('ws://127.0.0.1:3000/get_loop');
        var terminal = document.getElementById('terminal');
        ws.onopen = function() {
            ws.send('start');
        };
        ws.onmessage = function(event) {
            var msg = event.data;
            terminal.innerHTML += msg;
        };
    </script>
</body>
</html>

在这个例子中,我有一个从 0 到 14 的循环计数。我试图通过网络套接字将每个计数发送到 textarea,以便在循环计数时显示。该循环在我的实际应用程序中模拟 CLI 响应。这甚至可以通过网络套接字完成吗?

-编辑-

修改上面的 web socket 代码,使用Mojo::IOLoop-&gt;recurring 就可以解决问题,而不必求助于多线程。

websocket '/get_loop' => sub {

    my $c = shift;

    $c->app->log->debug("Websocket opened");

    my $id;
    $c->on(message => sub {

        my ($c, $msg) = @_;

        my $count = 0;
        $id = Mojo::IOLoop->recurring(1 => sub {
            $c->send("$count\n");
            $c->app->log->debug($count);
            sleep (1);
            $c->finish if $count++ == 10;
        });
    });

    $c->on(finish => sub {
        my ($c, $code, $reason) = @_;
        Mojo::IOLoop->remove($id);
        $c->app->log->debug("WebSocket closed with status $code");
    });
};

【问题讨论】:

  • 是的,你可以做到……你应该这样做吗?你是怎么做到的?这些是与项目相关的细节......也许通过 websocket 传递原始数据并在客户端进行格式化,或者将解析的 HTML 从服务器传递给客户端......(我会做 A)......有很多不同的方法。
  • 我提供的示例显示我正在通过 Web 套接字将数据从服务器传递到客户端。问题是来自服务器的单个“计数”不会实时显示在文本区域中,因为服务器从零开始计数。相反,服务器会在循环完成后吐出所有内容。我应该在我的问题中更清楚地说明这一点。我在 Web 套接字之间来回传递数据没有问题,我只是不知道如何在服务器处于循环状态时实时发送数据。
  • 您显示的代码是否存在需要帮助的特定问题?
  • 这是因为 javascript 既是偶数又是单线程的——这意味着 send 会安排一个在您的代码退出循环之前不会被处理的事件。只要您的代码正在运行,就不会处理其他事件。我正在简化解释,但经验法则是“假设在您的代码返回之前没有任何事情发生”。附:哦,哎呀,我没有注意到服务器在perl,但是,同样的规则可能适用......?
  • 删除for循环并将其替换为my $id = Mojo::IOLoop-&gt;recurring(1 =&gt; sub {...});,并将循环内的内容放入子中(sleep除外,您可以删除它)。

标签: perl websocket


【解决方案1】:

您需要在页面上制作 javascript websocket 侦听器并将传递的数据插入 DOM。

const socket = new WebSocket('ws://localhost:8080');
socket.addEventListener('open', function (event) {
    socket.send('Hello Server!');
});

socket.addEventListener('message', function (event) {
    var div = document.getElementById('divID');
    div.innerHTML = event.data;
});

哦,我明白了,您的问题是关于服务器 Perl 代码的。我的建议是在 Perl 中创建一个静态连接数组,在打开事件时分配它们,在关闭事件时取消分配它们。您不需要在 on message sub 中将数据发回。您可以使用 Event::Lib $event->add( [$timeout] ) 然后枚举打开的套接字(到各种不同的 Web 客户端)调用 $c->send("$i\n");它完全是异步的,因此无需将其绑定到 on message sub。服务器可以随时执行此操作。

在 PERL 中创建静态变量: http://www.perlmonks.org/?node_id=8299

【讨论】:

    猜你喜欢
    • 2012-11-02
    • 2017-08-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-18
    • 2017-12-18
    • 1970-01-01
    • 1970-01-01
    • 2012-03-03
    相关资源
    最近更新 更多