【问题标题】:Chat application AJAX polling聊天应用 AJAX 轮询
【发布时间】:2010-09-07 07:44:13
【问题描述】:

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

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

以前有人做过类似的事情吗?你会推荐什么?

【问题讨论】:

    标签: php ajax chat


    【解决方案1】:

    您可能还想查看Comet

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

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

    【讨论】:

      【解决方案2】:

      你会推荐什么?

      通过 BOSH 的 XMPP

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

      【讨论】:

        【解决方案3】:

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

        【讨论】:

          【解决方案4】:

          您可能还想研究彗星。

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

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

          【讨论】:

            【解决方案5】:

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

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

            【讨论】:

              【解决方案6】:

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

              【讨论】:

                【解决方案7】:

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

                以下代码是我的“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);
                  }
                }
                

                【讨论】:

                • 这种技术是否需要 tomcat 添加第三个彗星库 ..etc ?或者可以在典型的 servlet 上服务?有没有我们可以参考的演示/工作应用程序?
                • 这种技术不需要 IIS6 和 .NET 以外的任何东西来启动和运行。
                【解决方案8】:

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

                【讨论】:

                  【解决方案9】:

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

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

                  【讨论】:

                    【解决方案10】:

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

                    【讨论】:

                      【解决方案11】:

                      结帐Speeqeopen-source solution 用于在后台使用 BOSH 和 XMPP 的基于 Web 的聊天室。

                      【讨论】:

                        【解决方案12】:

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

                        当您进行投票时,您应该注意会话行为 (race conditions)。为了简单起见:如果您打开一个会话,会话文件将被锁定,直到会话关闭,以避免 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>
                        

                        你可以试试here

                        【讨论】:

                          猜你喜欢
                          • 2013-08-14
                          • 1970-01-01
                          • 2011-07-15
                          • 2011-02-27
                          • 1970-01-01
                          • 2015-03-05
                          • 2012-11-06
                          • 2013-03-28
                          • 1970-01-01
                          相关资源
                          最近更新 更多