代码之家  ›  专栏  ›  技术社区  ›  Francisco Soto

聊天应用程序AJAX轮询

  •  14
  • Francisco Soto  · 技术社区  · 16 年前

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

    12 回复  |  直到 6 年前
        1
  •  7
  •   Ryan Guest    16 年前

    你可能还想调查一下 Comet .

    other chat applications . 几年前,当我尝试它时,没有太多的库或关于服务器体系结构的细节来实现它,但现在看起来有更多的东西。

    看一看这本书 cometd

        2
  •  5
  •   John Millikin    16 年前

    你推荐什么?

    XMPP通过波什

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

        3
  •  3
  •   Svante Svenson    16 年前

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

        4
  •  2
  •   Community CDub    4 年前

    你们可能还想看看彗星。

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

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

        5
  •  2
  •   zuber    16 年前

    Comet ) - Orbited

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

        6
  •  1
  •   moonshadow    16 年前

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

        7
  •  1
  •   Toran Billups    16 年前

    几个月前,我也做了同样的事情,只是在玩弄这些概念。实际上我用的是 forever-frame

    下面的代码是我的“comet”js文件,其中包含获得“party chat”设置所需的一般概念。

    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);
      }
    }
    
        8
  •  0
  •   hoyhoy    16 年前

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

        9
  •  0
  •   UnkwnTech    16 年前

    我同意约翰的观点。但还有一个问题没有得到回答。

    编辑:顺便说一句,当我接到电话时,戈达迪听上去不那么好笑。

        10
  •  0
  •   Jimmy    16 年前

    我认为投票是最简单的方法,我建议先这样做。如果负载成为问题,开始研究更复杂的技术。 这里有一个很好的正反两方面的讨论- http://www.infoq.com/news/2007/07/pushvspull
    http://ajaxian.com/archives/a-report-on-push-versus-pull

        11
  •  0
  •   melo    16 年前

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

        12
  •  0
  •   Alain    12 年前

    我刚刚发现这篇文章,它很古老,但投票的概念给很多人带来了麻烦。因此,我将在这里给出一个实现示例。但在给你之前,我应该给你一个让我很生气的建议:

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

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