【问题标题】:Websockets - Getting Data (Polling?)Websockets - 获取数据(轮询?)
【发布时间】:2016-01-08 18:09:34
【问题描述】:

对于一些已经对此有所了解的人来说,这可能是一个愚蠢的问题,也许我只需要更多

问题:无论是使用 还是,似乎仍在进行一些轮询。这是正确的吗?

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

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

详情:我一直只使用,所以我决定检查一下整个websockets,据我所知,数据是实时发送到客户端的,但是,如上所述,除非我在这里遗漏了什么或一些逻辑,似乎我仍然必须告诉 来检查数据的间隔,否则数据将在无限循环中发送(想象一下调用 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 );
};

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

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

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

编辑: 未来的访问者,对此的回答是:当用户发送更改时,您将更改发送到打开的连接,而不是专门观察更改。

【问题讨论】:

  • 一般来说,websocket/socket 的目的是保持一个始终打开的恒定连接,所以在聊天程序的情况下..客户端在接收数据时,他们通过不必每隔几秒钟轮询/发布到服务器以显示响应来节省带宽。只需等待并触发收到的事件。关于监视服务器端文件,这需要轮询。但是服务器本身会轮询文件并向所有客户端发送更新,而不是所有客户端每隔几秒钟检查一次服务器,这里的 Websockets 仍然会为您节省带宽。
  • 我完全理解 websockets 的用途。问题是关于新内容的轮询以及其背后的逻辑如何运作。
  • 如前所述,您仍然可以让 PHP 在本地轮询文件,然后在检测到更改时通知客户端,告知您如何轮询文件。这可能会有所不同,您可以使用 CRON 作业,但需要在另一个威胁/php 脚本上运行套接字服务器。可能使用php.net/manual/en/function.fam-monitor-file.php,否则我只会在套接字服务器的主循环中运行类似 FAM 函数的东西, 如果检测到,则发送到所有消息。
  • 澄清一下,您正在回答这部分“问题:无论是使用 websockets 还是 ajax,似乎仍有一些轮询发生。这是正确的吗?”用“是”?
  • 对于纯客户端和服务器通信,没有轮询。为了让 PHP 能够检测到服务器端文件的变化,是的,会有某种形式的轮询。让 1000 个客户端全部 ajax 轮询您的服务器,每个触发服务器检查 = 1000 次检查文件。 Websocket 只是服务器在自己的循环中轮询并在为真时发送消息。所以套接字在这里更适合您的需要。至于文件,它只是用于检查文件是否已更改的标准 php 代码。

标签: coffee websockets ajax xmlhttprequest php javascript php javascript php websocket phpwebsocket


【解决方案1】:

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

就您的示例而言,如果您控制写入文件的操作,则可以调用 websocket“广播”或“发布”此事件。

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

由于我讨厌使用 PHP(无意冒犯,我只是把它填满了),这是一个使用 Plezi Real-Time Framework 的快速 Ruby 示例。

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

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

要运行此示例,请使用[sudo] gem install plezi 安装plezi gem(取决于您是否需要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

现在在两个不同的浏览器窗口中访问:

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

【讨论】:

  • 我现在明白了。通过在上面睡觉并查看您在 2 个浏览器窗口中访问的响应。我想我是在考虑一个老式的用户。当一个用户发送更改时,我不会关注更改,而是更新所有客户端。我知道我想错了。
  • 我意识到我的答案可能已经过时(正如我 5 年前写的那样).. 但为什么要在 2020 年 11 月(5 年后)否决它呢?为什么不发表评论,这样我就可以解决任何“错误”(如果有的话)......?‍♂️
  • 我只能假设有人用 php 标签热搜索 websocket php 的东西,并看到了不可复制粘贴的 ruby​​ 代码
【解决方案2】:

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

$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 文件(可能是 dameon)。它会在像上面这样的简单循环中每秒监视文件.. 如果有变化,我会让它通知另一个 PHP 脚本/线程将内容发送给所有客户端。

如果同一个文件被发送到所有客户端,这不会很糟糕。因为你可以使用发送到所有功能。但是如果每个客户端不同(比如他们自己的历史/日志)。它需要每个客户端的处理,这将对性能造成一点影响。

为了进一步证明这样的事情,您将记录客户端上次接收文件内容的时间并限制再次发送它之前的时间。因此客户端仅在 10 秒分钟后获得新副本,少了什么,它就会忽略。

这是什么范围/规模和类型的项目?

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

我个人觉得 PHP 不应该永远循环运行,它只是感觉不应该如何使用它。

【讨论】:

  • 完全是使用我的示例解决此问题的有效方法(这仅在示例中有效,这不是我要执行的实际任务,它只是一个示例)。老实说,我认为您并没有完全理解这个问题。
  • 进一步解释?如果我们不在同一级别atm可以理解
  • 我并不是专门寻找观看文本文件的特定解决方案。
  • PHP 将等待任务完成,然后继续执行下一行代码,它确实具有线程能力,但不适合使用它们。基本上,对于这个例子,它会工作。 . 但是每个客户都会排队,随着时间的推移,这会落后。对于多客户端监控服务器,我使用了 python,它允许我使用标准队列对每个客户端使用真正的事件/控制。 PHP 在这里将非常有限,并且不是用于此类目的的理想语言/解决方案。 (这里是个人经验)
【解决方案3】:

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

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

【讨论】:

  • 我真的希望不要收到非节点 js 问题的节点 js 响应。我知道节点 js,这个问题是关于 PHP 而不是专门关于库的。具体来说,它是关于轮询新内容的工作方式,在 PHP 中,没有库,而不是在节点 JS 中。这更适合作为评论
  • 我无法忍受现在一切都指向 node.js 的事实。用 PHP 制作 websocket 服务器很容易,它只需要人们能够编程而不是安装另一个该死的库...... Python 最终成为了我对 websocket 服务器的选择,因为它需要更多的控制和更少的资源。
  • @Mayhem - 我完全同意。就像看到一个 Javascript 问题,第一个答案是“你应该使用 jquery”。
  • 您要求一种无需轮询即可处理“实时”的方法,我建议使用基于事件的模型。 PHP 确实有一个用于 inotify 的包装器,如果您正在严格处理监视文件。轮询这里最大的问题是你正在敲击磁盘来读取文件,我相信你知道 IO 可能是一个大瓶颈。
  • Javascript 是一种基于事件的编程语言,因此建议。
猜你喜欢
  • 2013-08-11
  • 1970-01-01
  • 2011-06-18
  • 2012-07-07
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 2011-09-11
  • 2017-11-30
相关资源
最近更新 更多