在线聊天使用轮询

3

我需要在进行在线聊天时得到帮助。我已经创建了一个简单的在线聊天,其中一个用户可以与另一个用户通信,并将他们的对话保存为json文件。每隔2秒钟,我使用setInterval()重新加载json文件。用户发送的消息通过使用ajax和php函数fopen和fwrite(追加)进行发布并附加到json文件上。

我的问题是我的ajax发送/发布过程太慢了。在用户在聊天屏幕(div)上看到他/她的消息被发送之前需要一段时间。我尝试将消息附加到屏幕上,使其看起来像已经发送,但问题是当setInterval重新加载聊天屏幕并且新添加的消息尚未保存在json文件中时,新发送的消息将不会包括在该重新加载中。

问题:

  1. 如何更快地附加新消息?
  2. 当用户输入和发送消息过快时,如何排队多个ajax请求?
  3. PS:是否有更好的创建在线聊天的方法?我已经阅读了关于我的聊天使用轮询的文章,更好的方法是使用socket,但我不知道如何使用它。您是否有更好的方法或更好的逻辑?

2
你为什么不使用数据库呢?这会容易得多。 - Ry-
我没有使用数据库,因为我认为保存每个消息会填充我的数据库。 - jroi_web
它将填充您的数据库:) 它不会占用太多空间 - 可能比平面文件多约32KB左右 - 您将享受到好处。 - Ry-
3个回答

5

需要考虑以下几点:

-> 搜索长轮询(COMET)的相关内容。

-> 为什么要用setInterval来刷新屏幕,应该只需在服务器上添加新消息即可。

-> 如果您使用基于HTML5的浏览器,请查看Websockets和服务器端事件。

-> 在服务器端使用数据库操作,而不是文件操作。这也将提高可维护性,考虑一种情况,即1000个不同的用户正在互相聊天,那么维护这些文件将会很困难。

-> 服务器应该发送增量消息,而不仅仅是重新发送整个对话以供客户端解析和重新加载。


1
同时,使用数据库可能比XML或JSON对象更快。 - C0D3
是的,追加比刷新整个页面更好。谢谢!至于WebSockets,我还不能使用它,因为我需要HTML5,而且有很大的可能性用户没有使用它。 - jroi_web
我同意数据库应该比文件操作更快...谢谢c0d3Junk13。 - Nitin Midha

0

我最近才做了这个,这是代码

index.php

<?php 
    session_start();

    if(isset($_GET['logout'])) {
        session_destroy();
        header("Location: index.php"); //
    }

    if(isset($_POST['username'])) {
        if(trim($_POST['username']) != "") {
            $_SESSION['username'] = stripslashes(htmlspecialchars($_POST['username']));
            header("Location: index.php"); //
        } else {
            header("Location: index.php"); //
        }
    }
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="zh-CN">
<head profile="http://gmpg.org/xfn/11">
<title>chating</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />   
<link rel="stylesheet" href="style.css" type="text/css" media="screen" />
<script type="text/javascript" src="jquery-1.5.min.js"></script>
<!--[if IE]>
<script type="text/javascript" src="jquery.corner.js"></script>
<script type="text/javascript">
$("#main,#login").corner("15px");
</script>
<![endif]-->

<script type="text/javascript">
//<![CDATA[
$(document).ready(function() {

    //$("#main,#login").corner();

    $("#message").focus();

    $("#logout").click(function() {
        if(confirm("Are you sure to exit this chat?")) {
            window.location = "index.php?logout=yes";
        }
    });

    $("#btnsend").click(function() {

        //$("#chathistory").append("<div>" + $("#message").val() + "</div>");
        //alert($("#chathistory").html());

        if($("#message").val() == "") {
            alert("Please input something !");
            return false;
        }

        $.post("ajax.php", {message: $("#message").val()});

        $("#message").val("");
        $("#message").focus();

        return false;
    });

    $("#message").keydown(function(e) {
        if (e.ctrlKey && e.keyCode == 13) {
            $("#btnsend").click();

        }
        //alert(e.keyCode);
    });


    function loadChatHistory() {
        var oldscrollHeight = $("#chathistory").attr("scrollHeight") - 20;

        $.ajax({
            url: "ajax.php?type=getmsg",
            cache: false,
            dataType: "xml",  
            success: function(xmlData) {

                var htmlData = "";
                $(xmlData).find("Msg").each(function() {
                    htmlData += '<div><span class="people">' + $(this).find("MsgFrom").text() + "  " +  $(this).find("MsgDateTime").text() +  '</span><p class="content">' + $(this).find("Message").text() + '</p></div>'
                });

                $("#chathistory").html(htmlData);
                var newscrollHeight = $("#chathistory").attr("scrollHeight") - 20;

                if(newscrollHeight > oldscrollHeight) {
                    $("#chathistory").animate({ scrollTop: newscrollHeight }, 'normal');
                }

            }
        });




    }

    setInterval (loadChatHistory, 2500);
});
//]]>
</script>
</head>
<body>
<?php
    //print_r(var_dump($_SESSION));
?>
<?php
    if(!isset($_SESSION['username'])) {
?>
    <div id="login">
        <form action="index.php" method="post">
            <label for="username">UserName:</label>
            <input type="text" id="username" name="username" class="corner2"/>
            <input type="submit" id="btnlogin" name="btnlogin" class="corner2" value="Login"/>
        </form>
    </div>
<?php
    } else {
?>
    <div id="main">

        <p id="welcome">Welcome, <strong><?php echo $_SESSION['username'] ?></strong></p>
        <p id="logout"><a href="#">Exit Chat</a></p>
        <div class="clear"></div>
        <div id="chathistory" class="corner2">

        </div><!-- #chathistory -->

        <div id="userlist" class="corner2">

        </div><!-- #userlist -->

        <div id="chatarea" class="corner2">
            <textarea id="message" class="corner2" rows="2" cols="2"></textarea>
        </div><!-- #chatarea -->
        <div id="send">
            <input type="button" id="btnsend" value="Send!" class="corner2" />
        </div>
        <div class="clear"></div>

    </div><!-- #main -->
<?php
    }
?>
</body>
</html>

ajax.php

<?php

    session_start();
    date_default_timezone_set("PRC");

    if(isset($_SESSION["username"])) {
        $dbh = new pdo("sqlite:./Message.DB");

        if(isset($_GET["type"]))
        {

            if($_GET["type"] == "getmsg") {

                $strXML = '<?xml version="1.0" encoding="utf-8" ?>';
                $strXML .= "<Msgs>";

                foreach($dbh->query("select * from (SELECT  * FROM Message ORDER BY MsgID DESC limit 0,500) ORDER BY MsgID ASC") as $row) {
                    $strXML .= "<Msg>";
                    $strXML .= "    <Message>" . stripslashes(htmlspecialchars($row[1])) . "</Message>";
                    $strXML .= "    <MsgDateTime>" . $row[2] . "</MsgDateTime>";
                    $strXML .= "    <MsgFrom>" . stripslashes(htmlspecialchars($row[3])) . "</MsgFrom>";
                    $strXML .= "</Msg>";
                }

                $strXML .= "</Msgs>";
                echo $strXML;

            } 
        } else {

            $message = $_POST["message"];   
            $message = str_replace("'","''",$message);

            $SQL = "INSERT INTO Message(Message, MsgDateTime, MsgFrom) VALUES('" . $message . "', '" . date("Y-m-d H:i:s") . "','" . str_replace("'","''",$_SESSION["username"]) . "')";
            //echo $SQL;
            $dbh->query($SQL);
        }
    }
?>

style.css

* {
    margin: 0;
    padding: 0;
}

body {
    font-family: LucidaGrande, Tahoma, Verdana, Arial, IPAPGothic, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    background-color: #EDE8E2;
}



#main ,#login {
    width: 600px;
    margin: 30px auto;
    padding: 20px;
    background-color: #A8B6D3;

    -moz-box-shadow: 10px 10px 5px #888888; 
    -webkit-box-shadow: 10px 10px 5px #888888; 
    box-shadow: 10px 10px 5px #888888;

    -moz-border-radius:15px;
    border-radius:15px;
}

#login {
    text-align:center;
}

#login input[type="text"] {
    border:0;
    padding:5px;
}

#login input[type="submit"] {
    border:0;
    border:2px solid #5D92D0;
    background-color: #A8B6D3;
    padding:2px;
    font-family: LucidaGrande, Tahoma, Verdana, Arial, IPAPGothic, sans-serif;
    font-size: 14px;
}

#welcome {
    margin-bottom: 10px;
    float:left;
}

#logout {
    text-align:right;
    font-weight:bold;
}

#chathistory {
    background-color: #fff;
    width: 450px;
    height: 250px;
    padding: 4px 10px;
    float: left;
    overflow: auto;
}

#chathistory span.people {
    color:#008040;
    margin-right:10px;
}

#chathistory p.content {
    margin-left:20px;
}

#userlist {
    background-color: #fff;
    margin-left: 480px;
    padding: 4px 10px;
    width:100px;
    height: 250px;
    overflow: auto;
}

#userlist ol {
    list-style-type: none;
}

#chatarea {
    background-color: #fff;
    margin-top:15px;
    height:70px;
    width:470px;
    padding: 0;
    float:left;
}

#message {
    width: 460px;
    height:62px;
    resize: none;
    border: 0;
    padding: 4px 0 4px 10px;

    font-family: LucidaGrande, Tahoma, Verdana, Arial, IPAPGothic, sans-serif;
    font-size: 14px;
    line-height: 1.4;

    overflow:auto;
}

#btnsend {
    width:120px;;
    height:70px;
    margin-left: 10px;
    margin-top:15px;
    border:2px solid #5D92D0;
    background-color: #A8B6D3;
    font-family: LucidaGrande, Tahoma, Verdana, Arial, IPAPGothic, sans-serif;
    font-size: 28px;
    font-weight:bold;
}

.corner2 {
    -moz-border-radius:5px;
    border-radius:5px;
}

.clear {
    clear:both;
}

附注,我使用了SQLite数据库


0

你应该使用数据库而不是平面文件,因为如果尝试同时读写文件可能会出现问题,并且每两秒解析整个json格式的对话需要不必要的处理。我建议使用sqlite,因为它易于设置,不需要任何特殊的数据库服务器软件,然后您只需查询选择最后一次刷新后发送的当前对话的所有消息即可,您的查询将类似于:

获取消息:

mysql_query("SELECT * FROM `chat` WHERE `id` == '".$id."' AND `timestamp` > '".$lastfetch."'");

发送消息:

$timestamp = time();
mysql_query("INSERT INTO `chat` (`id`,`message`,`timestamp`) VALUES('".$convoid."', '".$message."', '".$timestamp."')");
echo $timestamp;

然后,您将在JavaScript中将回显的时间戳保存到变量中,然后将其作为$lastfetch发送到下一个ajax获取请求中,因此您的查询将获取自上次检查以来的所有新消息。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接