Websockets - 获取数据(轮询?)

Websockets - Getting Data (Polling?)

对于一些已经思考过这个问题的人来说,这可能是一个愚蠢的问题,也许我只需要更多

问题: 是否使用 or 似乎仍有一些轮询发生。这是正确的吗?

示例 (不是真正的项目):我想关注一个文本文件。除非我遗漏了什么(更多的咖啡?),我不是还需要 a) 询问服务器是否有更新,或者 b) 告诉页面我有更新;通过让 PHP 代码休眠一段时间或在客户端有一个 setTimeout 循环。

我确实理解的事情: 我确实看到了在服务器和页面之间来回交谈的好处。我看到我没有发送 http 请求。所以我看到了好处。

详情: 我一直只使用 so I decided to check out this whole websockets thing as from what I thought I understood, is that data is sent to the client in real time, but, like stated above, unless I am missing something or some logic here, it seems like I still have to either tell or 来检查数据的间隔,否则数据将在无限循环中发送(想象一下调用 mysql).

也许我的代码逻辑有问题。欢迎您查看。从我找到的所有例子来看,每个人似乎都只是 运行 PHP

中的无限循环

PHP(减去所有连接行话)

while(true) {
    // update once a second
    $this->send($client, file_get_contents('/my/file/test.txt'));
    sleep(1);
}

Javascript

var websocket = new WebSocket( "ws://mysite.com:12345" );

websocket.onmessage = function( str ) {
    console.log( str.data );
};

我只是没有掌握关于如何在没有某种轮询的情况下使其实时的逻辑。也许这就是它应该的工作方式。

我明白,如果我从 代码中删除睡眠,事情就会变得更加实时,太多了,但这似乎会无限地轮询上面示例中的文件,但事实并非如此。好像不对。

编辑: 澄清一下,我并不是专门寻找观看文本文件的特定解决方案。如果您浏览了这个问题,您可能已经想到了这一点。

编辑: 未来的访问者,对此的答案是:当用户发送更改时,您发送更改以打开连接,而不是专门监视更改。

这里需要基于事件的编程。使用为您处理事件的库会容易得多。 PHP 不是此类编程的最佳工具,但可能仍然有适合它的库。

一个解决方案是拥有一个 nodejs/socket.io 服务器,当发生有趣的事情时,您的 php 进程可以向它发送消息。然后 nodejs 服务器会将其传递给客户端。

最初我会建议类似的东西。

$sFile = "/my/file/test.txt";
$timeMod = filemtime($sFile);
while(true) {
    if (filemtime("SomeFileHere.txt")!==$timeMod ) {
        $timeMod = filemtime($sFile);
        // File has changed, update variable with new timestamp
        $this->send($client, file_get_contents($sFile));
    } else {
        // No change, do nothing here.
    }
    sleep(1);
}

基本上在你循环之前,你会得到最后修改日期.. 如果在循环中它发生了变化,我们会更新变量并在那时发送警报。

如果尝试在现实世界中做一些类似于此的工作而没有任何负载问题,我会在一个循环中有一个 PHP 文件 运行ning(可能是 dameon).. 这会像上面一样在一个简单的循环中每秒监控一次文件。如果有变化,我会让它通知另一个 PHP script/thread 将内容发送给所有客户端。

如果同一个文件被发送到所有客户端,这不会太糟糕。因为您可以使用发送到所有功能。但是如果每个客户端不同(比如他们自己的 history/log)。 . 这将需要对每个客户端进行处理,这会稍微影响性能。

为了进一步验证此类内容,您可以记下客户端最后一次收到文件内容的时间,并限制可以再次发送文件内容的时间。因此,客户端只会在 10 秒后获得一份新副本分钟,少了它就忽略了。

这是什么scope/scale项目类型?

目前我的 python 服务器可以接收来自 20,000 个客户端的请求并处理他们的数据并在一秒内回复所有...(GPS 处理)。虽然我每次都不会发送超过 1 KB 的任何内容,但在 python 中进行线程化和排队的能力将使它成为一种更好的方法,并且可以在一个实例中处理这么多客户端。随着时间的推移,只使用了大约 130mb 的 ram,没有内存泄漏

PHP我个人觉得不应该运行一直循环下去,就是感觉不应该怎么用。

Websockets 允许您完全避免轮询,只要您控制所有事件(或 Sub/Pub 到外部事件)。

对于您的示例,如果您控制写入文件的操作,那么您可以调用 websocket "broadcast" 或 "publish" 此事件。

通过这种方式,您可以完全避免轮询。

由于我讨厌使用 PHP(无意冒犯,我只是受够了),这里有一个使用 Plezi Real-Time Framework.

的快速 Ruby 示例

在此示例中,我们使用简单的 touch 方法来执行操作。虽然我并没有真正接触文件,但您可以体验到 API 的使用允许我控制事件并向其他用户广播 - 不涉及轮询

如果我订阅外部事件,情况也是如此。

对于运行这个例子,使用[sudo] gem install plezi安装plezigem(取决于你是否需要sudo和你的系统)并打开IRB 终端使用终端中的 irb 命令。比粘贴以下代码:

需要'plezi'

class RootController
    def index
        %{<html><head>
<script>
    var websocket = NaN;
    function connect() { websocket = new WebSocket( (window.location.protocol.match(/https/) ? 'wws' : 'ws') + '://' + window.location.hostname + (window.location.port == '' ? '' : (':' + window.location.port) ) + "/" ); }
    function init()
    {
        connect()
        websocket.onopen = function(evt) { WriteMessage("(Connected and waiting for messages)", "connection") };
        websocket.onclose = function(evt) { WriteMessage("(Disconnected. messages will be lost)", "connection");connect();  };
        websocket.onmessage = function(evt) {
            WriteMessage(evt.data, "");
        };
        websocket.onerror = function(evt) { WriteMessage(evt.data, 'error'); };
    }
    function WriteMessage( message, message_type )
    {
        if (!message_type) message_type = 'received'
        var msg = document.createElement("p");
        msg.className = message_type;
        msg.innerHTML = message;
        document.getElementById("output").appendChild(msg);
    }
    function Send(message)
    {
        WriteMessage(message, 'sent'); 
        websocket.send(message);
    }
    window.addEventListener("load", init, false);
  </script></head>
<body>
<p>Messages should show up here:</p>
<div id=output></div>
</body>
</html>
        }
    end
    def touch
        FileController.touch
        "You Touched the file, a message should be sent to the web browser windows."
    end
    def on_open
        subscribe :file_notifications
    end
    def on_message data

    end
    def self.push_update_event
        publish :file_notifications, "The file was updated."
        "Touched - Ok".freeze
    end
end

class FileController
    def self.touch
        puts "INFO: A file should be touched.. you can do whatever you feel like here..."
        RootController.push_update_event
    end
end

class APIController
    def touched
        RootController.push_update_event
    end
end

Plezi.route '/', RootController
Plezi.route '/api', APIController

exit # the server will start once you exit the irb terminal

现在访问,在两个不同的浏览器中windows:

或者,您甚至可以 "edit the file"(虚拟地)使用外部脚本,然后访问 http://localhost:3000/api/touched 以通知所有用户该操作(此处未显示身份验证,但应添加).