我目前正在参与的项目中,我们需要开发一个 web 聊天应用,不是非常复杂的聊天,只是一个让两个人聊特定话题的方式,我们不需要任何一方用户进行身份验证,也不需要支持表情符号、头像等其他内容。
一些项目成员建议我们可以通过 BOSH 使用 XMPP,但我认为这就像用渔网去捕鱼一样,提出了一个更简单的方法,比如使用简单的 Ajax/MySQL web 聊天,但我们担心由于同时打开多个聊天窗口所导致的服务器性能损耗。
有人做过类似的事吗?你会推荐什么呢?
你会推荐什么?
通过BOSH使用XMPP
如果有人已经发明了消息格式和传输协议,那么就没有必要再去发明。如果你尝试发明自己的协议,它将逐渐变得与BOSH一样复杂,但却没有第三方库支持或标准化的好处。
你可能还想了解Comet。
我认为大家都在使用cometd来处理这种情况。
BOSH是一种将XMPP通过HTTP传输的标准。它利用Comet将数据推送到客户端。
几个月前,我也做过同样的事情,只是玩弄这些概念很有趣。实际上,我使用了forever-frame技术而不是轮询。
以下代码是我的“彗星”js文件,其中包含了设置“聚会聊天”所需的一般概念。
function Comet(key) {
var random = key;
var title = 'Comet';
var connection = false;
var iframediv = false;
var browserIsIE = /*@cc_on!@*/false;
var blurStatus = false;
var tmpframe = document.createElement('iframe');
var nl = '\r\n';
this.initialize = function() {
if (browserIsIE) {
connection = new ActiveXObject("htmlfile");
connection.open();
connection.write("<html>");
connection.write("<script>document.domain = '"+document.domain+"'");
connection.write("</html>");
connection.close();
iframediv = connection.createElement("div");
connection.appendChild(iframediv);
connection.parentWindow.comet = comet;
iframediv.innerHTML = "<iframe id='comet_iframe' src='./comet.aspx?key="+random+"'></iframe>";
} else {
connection = document.createElement('iframe');
connection.setAttribute('id', 'comet_iframe');
iframediv = document.createElement('iframe');
iframediv.setAttribute('src', './comet.aspx?key='+random);
connection.appendChild(iframediv);
document.body.appendChild(connection);
}
}
// this function is called from the server to keep the connection alive
this.keepAlive = function () {
if (!browserIsIE) {
mozillaHack();
}
}
// this function is called from the server to update the client
this.updateClient = function (value) {
var outputDiv = document.getElementById('output');
outputDiv.value = value + nl + outputDiv.value;
if (blurStatus == true) {
document.title = value;
}
if (!browserIsIE) {
mozillaHack();
}
}
this.onUnload = function() {
if (connection) {
// this will release the iframe to prevent problems with IE when reloading the page
connection = false;
}
}
this.toggleBlurStatus = function(bool) {
blurStatus = bool;
}
this.resetTitle = function() {
document.title = title;
}
function mozillaHack() {
// this hack will fix the hour glass and loading status for Mozilla browsers
document.body.appendChild(tmpframe);
document.body.removeChild(tmpframe);
}
}
我刚刚发现了这篇文章,虽然它有点老,但是轮询的概念对很多人来说都很困扰。所以我会在这里放一个实现示例。但在给你之前,我应该给你一个建议,因为有一次让我很生气:
当你进行轮询时,你应该注意会话行为(竞态条件)。简单来说:如果你打开一个会话,会话文件将被锁定,直到会话关闭,以避免两个线程写入不同的数据。因此,如果你需要一个会话来检查用户是否已登录等信息,请在轮询之前始终关闭会话。
我的演示为你提供了一个PHP中轮询实现的示例。我不会使用数据库,而是使用文件。当你点击轮询按钮时,你将进入循环,直到文件被修改,你将一直轮询。当你填写表单并点击“释放”时,你输入的内容将保存到文件中。文件的修改时间将改变,因此轮询将停止。
提示:使用类似Firebug的工具来查看发生了什么。
现在让我们用比我的英语更好的语言交流:
<?php
// For this demo
if (file_exists('poll.txt') == false) {
file_put_contents('poll.txt', '');
}
if (isset($_GET['poll'])) {
// Don't forget to change the default time limit
set_time_limit(120);
date_default_timezone_set('Europe/Paris');
$time = time();
// We loop until you click on the "release" button...
$poll = true;
$number_of_tries = 1;
while ($poll)
{
// Here we simulate a request (last mtime of file could be a creation/update_date field on a base)
clearstatcache();
$mtime = filemtime('poll.txt');
if ($mtime > $time) {
$result = htmlentities(file_get_contents('poll.txt'));
$poll = false;
}
// Of course, else your polling will kill your resources!
$number_of_tries++;
sleep(1);
}
// Outputs result
echo "Number of tries : {$number_of_tries}<br/>{$result}";
die();
}
// Here we catch the release form
if (isset($_GET['release']))
{
$data = '';
if (isset($_GET['data'])) {
$data = $_GET['data'];
}
file_put_contents('poll.txt', $data);
die();
}
?>
<!-- click this button to begin long-polling -->
<input id="poll" type="button" value="Click me to start polling" />
<br/><br/>
Give me some text here :
<br/>
<input id="data" type="text" />
<br/>
<!-- click this button to release long-polling -->
<input id="release" type="button" value="Click me to release polling" disabled="disabled" />
<br/><br/>
Result after releasing polling :
<div id="result"></div>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js"></script>
<script type="text/javascript">
// Script to launch polling
$('#poll').click(function() {
$('#poll').attr('disabled', 'disabled');
$('#release').removeAttr('disabled');
$.ajax({
url: 'poll.php',
data: {
poll: 'yes' // sets our $_GET['poll']
},
success: function(data) {
$('#result').html(data);
$('#poll').removeAttr('disabled');
$('#release').attr('disabled', 'disabled');
}
});
});
// Script to release polling
$('#release').click(function() {
$.ajax({
url: 'poll.php',
data: {
release: 'yes', // sets our $_GET['release']
data: $('#data').val() // sets our $_GET['data']
}
});
});
</script>
我认为轮询是最简单的方法,建议首先使用它。如果负载成为问题,可以考虑更复杂的技术。
有关利弊的讨论在这里 -
http://www.infoq.com/news/2007/07/pushvspull
http://ajaxian.com/archives/a-report-on-push-versus-pull