长时间轮询和会话(聊天)的问题


Issues with long polling and sessions (chat)

我做了一个朋友聊天,使用文本文件存储数据,这一切或多或少都能正常工作,除了当我登录并给某人写东西时,什么都不会弹出(但文本存储在适当的文本文件中),然后当我刷新页面时,从那时起就可以了,但在另一个浏览器上,作为另一个用户,我也必须刷新页面,以便它能够双向正常工作。

基本上,每次登录时,我都必须单击要聊天的人的姓名,然后会弹出一个窗口,然后我必须刷新,否则就不起作用了。

我想每当我点击朋友想和他聊天时,我都必须刷新页面,这是一个会话问题。

这里是home.php(用户登录index.php页面时会重定向到这里)

<?php
session_start();
if (!isset($_SESSION['user'])) {
    header("Location: index.php");
    exit();
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style type="text/css">@import 'custom_chat.css';</style>
</head>
<body>
<h2>Hello, <?php echo $_SESSION['user']; ?></h2>
<hr>
<p><b>CONTACTS:</b></p>
<?php
require_once 'dbc.php';
$u = $_SESSION['user'];
$q = "SELECT user_id FROM users WHERE username='$u'";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
// current user id
$uid = $row[0];
$q = "SELECT u.username FROM users AS u, friends AS f 
      WHERE (f.f1 = '$uid' OR f.f2 = '$uid') AND (f.f1 = u.user_id OR f.f2 = u.user_id) AND (u.username != '$u')";
$r = mysqli_query($dbc, $q);

while ($row = mysqli_fetch_assoc($r)) {
    echo '<div class=chat_contacts>';
    echo '<div class='.$row['username'].'>';
    echo '<div class=inner>';
    echo '<div class=inner_chat></div>';
    echo '<form>
              <textarea class=chat_text></textarea> 
          </form>       
          ';
    echo '</div>'; // end .inner
    echo '<a href="#" class='. $row['username'] .'>'.$row['username'] .'</a>
          </div>';
    echo '</div>'; // end .chat_contacts
}
?>
<p><a href="index.php">HOME</a></p>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/jquery-ui.min.js"></script>
<script type="text/javascript">
var nc = '<?php echo $u ?>';
// toggle chat window
$('.chat_contacts a').click(function() {
    $(this).prev('div.inner').toggle();
    var tc = $(this).attr('class');
    $(this).parent().parent().addClass(nc+tc);
    $('textarea').focus(); // MD maybe
    return false;
});
// call main chat function
$(function () {
    updateChat(); 
}); // end ready
//update on enter
$('textarea.chat_text').keypress(function(e) {
    $this = $(this); // textarea
    if (e.which == '13') {
        insertChat();

        return false;
    }
});
function insertChat() {
    var text = $this.val();
    $this.val('');
    var ru = $this.parent().parent().parent().attr('class');
    $.post('insert.php',{text:text, ru:ru}, function(data) {
        if (data) {
            alert(data)
        }
    });
}
var timestamp = 0;
function updateChat() {
    $.ajax({
        type: 'GET',
        url: 'update.php?timestamp=' + timestamp,
        async: true,
        cache: false,
        success:function(data) {
            // alert(data);
            var json = eval('('+data+')');
            // if (json['msg'] != null) {
                $('.chat_contacts.'+nc+json['nru']+' .inner_chat').append('<p>'+json['msg']+'</p>'); // MD
            // }
            timestamp = json['timestamp'];
            setTimeout('updateChat()', 1000);
        },
        error: function(XMLHttpRequest, textStatus, errorThrown) {
            // alert('error '+textStatus+'('+errorThrown+')');
            setTimeout('updateChat()', 1000);
        }
    });
}
</script>
</body>
</html>

update.php

<?php
session_start();
require_once('dbc.php');
error_reporting(E_ALL ^ E_NOTICE);
set_time_limit(0);
$ou = $_SESSION['user'];
$ru = $_SESSION['ru'];
session_write_close();
$q = "SELECT * FROM chats WHERE 
      (chats.f1='$ru' AND chats.f2='$ou') OR (chats.f1='$ou' AND chats.f2='$ru') ORDER BY time DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
// $filename = 'vojaolja.txt';
$q = "SELECT user_id FROM users WHERE username='$ou' 
      ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$fu = $row[0];
$q = "SELECT user_id FROM users WHERE username='$ru' ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$su = $row[0];
$q = "SELECT username FROM users WHERE username='$ru' ORDER BY user_id DESC LIMIT 1";
$r = mysqli_query($dbc, $q);
$row = mysqli_fetch_row($r);
$nru = $row[0];
if ($fu < $su) {
    $filename = $fu.$su.'.txt';
} else {
    $filename = $su.$fu.'.txt';
}
$lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0;
$currentmodif = filemtime($filename);
while ($currentmodif <= $lastmodif) {
    usleep(10000);
    clearstatcache();
    $currentmodif = filemtime($filename); 
}
$response = array();
$data = file($filename);
$line = $data[count($data)-1];
$response['msg'] = $line;
$response['nru'] = $nru;
$response['timestamp'] = $currentmodif;
echo json_encode($response);
?>

此外,如果有人想在自己的电脑上复制这个,我可以在这里发布所有的代码,它只是几页,它可以在2分钟内与数据库一起设置。

编辑:

我一登录,就在控制台中看到以下内容:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374509358392 (plus the rolling thingy, it is waiting)

然后我点击一个朋友的名字,弹出窗口,我写了一些东西,我在控制台上得到了这个:

http://localhost/x_super_chat/insert.php

然后当我再次刷新时(当它真正开始工作时),我在控制台中得到以下内容。

http://localhost/x_super_chat/update.php?timestamp=0&_=1374509491493
http://localhost/x_super_chat/update.php?timestamp=1374509435&_=1374509493231 + the waiting thingy icon, it is waiting

所以它在刷新后会发生变化,我需要刷新后得到的东西在我登录时就在那里

编辑2:(Pitchinnate回答后)

我一登录,就在控制台上看到这个:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566749185 (plus the waiting animation)

然后我给另一个人(比如约翰)写了一些东西,我得到了以下内容:

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566749185
http://localhost/x_super_chat/insert.php
http://localhost/x_super_chat/update.php?timestamp=0&_=1374566817682
http://localhost/x_super_chat/update.php?timestamp=1374565160&_=1374566817740
http://localhost/x_super_chat/update.php?timestamp=1374566817&_=1374566817801 (plus waiting animation)

然后,当我以John的身份在另一边写一些东西时,我得到了以下内容:(这是来自chrome的,所以它与firebug中的控制台不同):

http://localhost/x_super_chat/update.php?timestamp=0&_=1374566987051
http://localhost/x_super_chat/insert.php
http://localhost/x_super_chat/update.php?timestamp=1374566995&_=1374567004175
http://localhost/x_super_chat/update.php?timestamp=1374567004&_=1374567004215

您可以尝试的一件事是在插入时取消长轮询,在更新函数var myajax; 之外创建一个全局javascript变量

myajax = $.ajax({
    type: 'GET',
    url: 'update.php?timestamp=' + timestamp,

然后插入:

function insertChat() {
    myajax.abort();
    var text = $this.val();
    $this.val('');
    var ru = $this.parent().parent().parent().attr('class');
    $.post('insert.php',{text:text, ru:ru}, function(data) {
        if (data) {
            updateChat();
        }
    });
}