对于那些已经围绕它的人来说,这可能是一个愚蠢的问题,也许我只需要更多coffee。
问题:无论是使用websockets还是ajax,似乎仍然会发生一些民意调查。这是对的吗?
示例 (不是真正的项目):我想留意文本文件。除非我遗漏了一些东西(更多咖啡?),否则我仍然不得不 a)询问服务器是否有更新,或者 b)告诉我有更新的页面;通过将PHP代码暂停一段时间或在客户端进行setTimeout循环。
我明白的事情:我肯定看到在服务器和页面之间来回交谈的好处。我看到我没有发送http请求。所以我看到了好处。
详细信息:我一直只使用xmlhttprequest所以我决定从我认为理解的内容中查看整个websockets的内容,是否将数据发送到客户端时间,但是,如上所述,除非我在这里遗漏某些东西或某些逻辑,否则我似乎还是要告诉php或javascript检查数据的间隔,否则会发送数据在无限循环中(想象一下调用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代码中移除睡眠,事情会变得更加实时,太多,但这似乎会在上面的例子中无限地轮询该文件并且不会这样做。似乎是对的。
编辑:为了澄清,我并不是专门寻找观看文本文件的具体解决方案。如果你撇开这个问题,你可能已经想到了这一点。
编辑:未来的访问者,答案是:当用户发送更改时,您不会专门关注更改,而是将更改发送给打开的连接。
答案 0 :(得分:1)
Websockets允许您完全避免轮询,只要您控制所有事件(或Sub / Pub到外部事件)。
至于你的例子,如果你控制写入文件的动作,你可以调用websocket“广播”或“发布”这个事件。
通过这种方式,您可以完全避免轮询。
因为我厌恶使用PHP(没有冒犯,我只是填写了它),这是一个使用Plezi Real-Time Framework的快速Ruby示例。
在此示例中,我们使用简单的touch
方法来执行操作。虽然我没有真正触摸文件,但您可以体验到使用API可以控制事件并向其他用户广播 - 不涉及任何轮询。
如果我订阅外部事件,情况也是如此。
要运行此示例,请使用plezi
安装[sudo] gem install 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以通知所有用户该操作(此处未显示身份验证,但应添加此身份验证)。
答案 1 :(得分:0)
我最初会建议类似的东西。
$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秒后得到一个新的副本,什么都没有,只是忽略了。
到什么范围/规模&amp;项目类型是这个吗?
目前我的python服务器可以接收来自20,000个客户端的请求并处理他们的数据并在每秒内回复所有... ...(GPS处理)。虽然我每次都没有发送超过一千字节的任何内容,但是在python中进行线程和队列化的能力将使它成为一种更好的方法,并且可以在单个实例中处理这么多客户端。只使用大约130mb的ram,随着时间的推移没有内存泄漏
PHP我个人认为不应该在循环中运行,它只是感觉不应该如何使用。
答案 2 :(得分:-4)
此处需要基于事件的编程。使用为您处理事件的库会容易得多。 PHP不是这种类型编程的最佳工具,但可能仍然有一个库。
一个解决方案是拥有一个nodejs / socket.io服务器,并且当有趣的事情发生时,你的php进程可以向它发送一条消息。然后,nodejs服务器会将其传递给客户端。