在我目前正在开展的项目中,我们需要开发一个网络聊天应用程序,而不是一个非常复杂的聊天,只是一种联系两个人谈论一个非常具体的话题的方式,我们不需要任何对于这两个用户之一的身份验证,我们不必支持表情符号,头像或类似的东西。
一些项目成员建议我们可以通过BOSH使用XMPP,我说这就像尝试用船网捕鱼一样,并提出了一种更简单的方法,就像一个简单的Ajax / MySQL网络聊天,但我们很担心关于服务器中的性能损失,因为同时打开许多聊天的持续轮询。
以前有人做过这样的事吗?你会推荐什么?
答案 0 :(得分:7)
您可能还想查看Comet。
它被GTalk,Meebo和许多other chat applications使用。几年前,当我进行实验时,没有很多库或有关服务器架构的细节来实现它,但现在看起来还有很多东西。
查看cometd项目以获取更多技术信息。
答案 1 :(得分:5)
你会推荐什么?
XMPP到BOSH
当其他人拥有时,无需创建自己的消息格式和传输协议。如果你尝试,它会慢慢变得像BOSH一样复杂但没有第三方库支持或标准化的好处。
答案 2 :(得分:3)
如果你不喜欢HTTP轮询的想法,你可以在聊天页面上有一个Flash电影,它与服务器上的某个守护进程有一个持续的连接,然后Flash电影会调用它上面的JavaScript函数。客户端在新消息出现时更新聊天。 (除非你想要一个Flash界面进行聊天..)
答案 3 :(得分:2)
您可能还想查看Comet。
我认为每个人都喜欢这种东西。
BOSH是通过HTTP传输XMPP的标准。它涉及Comet将数据推送给客户。
答案 4 :(得分:2)
有一个非常好的服务器用于处理从服务器到浏览器的消息(称为Comet) - Orbited。它很容易与其他技术(Django,Rails,PHP等)集成,就像memcached一样。
如果你想处理严重的负荷,你真的应该检查它。否则,简单的Ajax轮询是最好的方法。
答案 5 :(得分:1)
几个月前我做了同样的事情,玩得很开心。我实际上使用了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);
}
}
答案 6 :(得分:1)
诀窍是要意识到你的应用程序需要在服务器上调用CGI的唯一时间就是有人说某事。对于常规民意调查,轮询一个静态页面,只要有新聊天,您的CGI脚本就会更新。使用HEAD请求,将时间戳与上次看到的时间戳进行比较,并在这些更改时仅执行完整的GET。我有一个简单的天真聊天应用程序以这种方式实现,并且我们拥有的几十个并发用户的负载和带宽使用率可以忽略不计。
答案 7 :(得分:0)
我认为每个人都喜欢这种东西。
答案 8 :(得分:0)
我同意约翰的观点。但还有另一个问题没有得到解答
我已经这样做了,但是我们使用平面文件而不是使用数据库,它最终使服务器瘫痪,但直到我们有~450个活跃用户,如果我们用数据库做了它,它可能会有所改善更好。
这是在Godaddy的基本托管账户上完成的。
编辑:当我接到电话时,BTW Godaddy听起来不那么有趣了。
答案 9 :(得分:0)
我认为民意调查是最简单的方法,并会先推荐。如果负载成为一个问题的开始,寻找更复杂的技术。
关于利弊的一个很好的讨论在这里 -
http://www.infoq.com/news/2007/07/pushvspull
http://ajaxian.com/archives/a-report-on-push-versus-pull
答案 10 :(得分:0)
结帐Speeqe。它是open-source solution基于Web的聊天室,在后台使用BOSH和XMPP。
答案 11 :(得分:0)
我刚刚发现这篇帖子,它很老了,但是民意调查给很多人带来了麻烦。所以我在这里提出一个实现示例。但是在给你之前,我应该给你一个让我生气的建议:
轮询时,您应该处理会话行为(race conditions)。为简单起见:如果打开会话,会话文件将被锁定,直到会话关闭,以避免2个theads将不同的数据写入其中。因此,如果您需要一个会话来检查用户是否已登录,请始终在轮询之前关闭会话。
我的演示为您提供了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>