Websockets - 获取数据(轮询?)
Websockets - Getting Data (Polling?)
对于一些已经思考过这个问题的人来说,这可能是一个愚蠢的问题,也许我只需要更多 coffee。
问题: 是否使用 websockets or ajax 似乎仍有一些轮询发生。这是正确的吗?
示例 (不是真正的项目):我想关注一个文本文件。除非我遗漏了什么(更多的咖啡?),我不是还需要 a) 询问服务器是否有更新,或者 b) 告诉页面我有更新;通过让 PHP 代码休眠一段时间或在客户端有一个 setTimeout 循环。
我确实理解的事情: 我确实看到了在服务器和页面之间来回交谈的好处。我看到我没有发送 http 请求。所以我看到了好处。
详情: 我一直只使用 xmlhttprequest 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 php or 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 代码中删除睡眠,事情就会变得更加实时,太多了,但这似乎会无限地轮询上面示例中的文件,但事实并非如此。好像不对。
编辑: 澄清一下,我并不是专门寻找观看文本文件的特定解决方案。如果您浏览了这个问题,您可能已经想到了这一点。
编辑: 未来的访问者,对此的答案是:当用户发送更改时,您发送更改以打开连接,而不是专门监视更改。
这里需要基于事件的编程。使用为您处理事件的库会容易得多。 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
安装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
现在访问,在两个不同的浏览器中windows:
或者,您甚至可以 "edit the file"(虚拟地)使用外部脚本,然后访问 http://localhost:3000/api/touched 以通知所有用户该操作(此处未显示身份验证,但应添加).
对于一些已经思考过这个问题的人来说,这可能是一个愚蠢的问题,也许我只需要更多 coffee。
问题: 是否使用 websockets or ajax 似乎仍有一些轮询发生。这是正确的吗?
示例 (不是真正的项目):我想关注一个文本文件。除非我遗漏了什么(更多的咖啡?),我不是还需要 a) 询问服务器是否有更新,或者 b) 告诉页面我有更新;通过让 PHP 代码休眠一段时间或在客户端有一个 setTimeout 循环。
我确实理解的事情: 我确实看到了在服务器和页面之间来回交谈的好处。我看到我没有发送 http 请求。所以我看到了好处。
详情: 我一直只使用 xmlhttprequest 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 php or 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 代码中删除睡眠,事情就会变得更加实时,太多了,但这似乎会无限地轮询上面示例中的文件,但事实并非如此。好像不对。
编辑: 澄清一下,我并不是专门寻找观看文本文件的特定解决方案。如果您浏览了这个问题,您可能已经想到了这一点。
编辑: 未来的访问者,对此的答案是:当用户发送更改时,您发送更改以打开连接,而不是专门监视更改。
这里需要基于事件的编程。使用为您处理事件的库会容易得多。 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
安装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
现在访问,在两个不同的浏览器中windows:
或者,您甚至可以 "edit the file"(虚拟地)使用外部脚本,然后访问 http://localhost:3000/api/touched 以通知所有用户该操作(此处未显示身份验证,但应添加).