14

在我目前正在做的项目中,我们需要开发一个网络聊天应用程序,不是很复杂的聊天,只是一种连接两个人谈论一个非常具体的话题的方式,我们不需要任何身份验证对于两个用户之一,我们不必支持表情符号、头像或类似的东西。

有项目成员建议我们可以通过BOSH来使用XMPP,我说这就像用船网捕鱼一样,并提出了一种更简单的方法,比如简单的Ajax/MySQL网络聊天,但我们担心性能由于不断轮询同时打开的许多聊天,因此在服务器中命中。

有没有人做过这样的事情?你会推荐什么?

4

12 回答 12

7

您可能还想研究Comet

GTalk、Meebo 和许多其他聊天应用程序都使用它。几年前,当我尝试使用它时,并没有很多库或有关服务器架构的详细信息来实现它,但现在看起来有更多的东西。

查看cometd项目以获取更多技术信息。

于 2008-08-30T00:29:37.490 回答
5

你会推荐什么?

XMPP 通过 BOSH

当别人有的时候,没有必要发明你自己的消息格式和传输协议。如果你尝试,它会慢慢变得和 BOSH 一样复杂,但没有第三方库支持或标准化的好处。

于 2008-08-30T00:22:22.577 回答
3

如果你不喜欢 HTTP 轮询的想法,你可以在聊天页面上有一个 Flash 电影,它与服务器上的某个守护进程保持持续连接,然后 Flash 电影会调用客户端上的 JavaScript 函数来更新新消息出现时的聊天。(除非你想为你的聊天使用 Flash 界面..)

于 2008-09-21T16:09:21.060 回答
2

您可能还想研究彗星。

我以为每个人都用 cometd 来做这种事情。

BOSH 是通过 HTTP 传输 XMPP 的标准。它涉及将数据推送到客户端的 Comet。

于 2008-08-30T02:04:27.590 回答
2

有一个非常好的服务器可以处理从服务器到浏览器的消息推送(称为Comet) - Orbited。它很容易与其他技术(Django、Rails、PHP 等)集成,就像 memcached 一样。

如果你想处理严重的负载,你真的应该检查它。否则,简单的 Ajax 轮询是最好的方法。

于 2008-09-21T14:34:31.863 回答
1

几个月前我也做过同样的事情,只是玩弄这些概念很开心。我实际上使用了永久帧技术而不是轮询。

下面的代码是我的“comet”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);
  }
}
于 2008-08-30T02:05:04.670 回答
1

诀窍是要意识到你的应用程序需要在服务器上调用 CGI 的唯一时间是有人说了什么。对于常规轮询,轮询一个静态页面,只要有新的聊天,CGI 脚本就会更新该页面。使用 HEAD 请求,将时间戳与上次看到的时间戳进行比较,并且仅在它们发生更改时执行完整的 GET。我有一个简单的以这种方式实现的简单聊天应用程序,对于我们拥有的几十个同时用户来说,负载和带宽使用可以忽略不计。

于 2008-09-21T14:38:08.050 回答
0

我以为每个人都用 cometd 来做这种事情。

于 2008-08-30T01:54:36.943 回答
0

我同意约翰的观点。但是还有一个问题没有回答。
我已经这样做了,但我们没有使用数据库,而是使用了平面文件,它最终确实削弱了服务器,但直到我们有大约 450 个活跃用户,如果我们使用数据库完成它可能会过得很好更好的。
这是在 Godaddy 的基本托管帐户上完成的。

编辑:顺便说一句,当我接到电话时,Godaddy 听起来不那么有趣。

于 2008-08-30T02:52:11.967 回答
0

我认为轮询是最简单的方法,并且会首先推荐。如果负载成为问题开始,请研究更复杂的技术。关于利弊的一个很好的讨论在这里 - http://www.infoq.com/news/2007/07/pushvspull
http://ajaxian.com/archives/a-report-on-push-versus-pull

于 2008-09-21T14:31:09.737 回答
0

结帐Speeqe。它是基于 Web 的聊天室的开源解决方案,在后台使用 BOSH 和 XMPP。

于 2009-05-06T10:57:51.173 回答
0

我刚找到这个帖子,它很旧,但是投票概念给很多人带来了麻烦。所以我会在这里放一个实现示例。但是在给你之前,我应该给你一个前段时间让我生气的建议:

轮询时,您应该注意会话行为(竞争条件)。为了简单起见:如果您打开一个会话,会话文件将被锁定,直到会话关闭,以避免 2 个线程将不同的数据写入其中。因此,如果您需要一个会话来检查用户是否已登录,请始终在轮询之前关闭会话。

我的演示为您提供了一个 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>

你可以在这里试试

于 2012-09-14T19:08:29.717 回答