我希望使用同时具有群聊和私人聊天功能的PHP / Javascript(Jquery)实现聊天室。
问题是如何以自然方式持续更新界面,还可能如何在私人聊天中显示“ X正在键入..”消息。
显而易见的方法似乎是,每隔X秒/毫秒,JavaScript将对服务器执行ping操作,并从上次ping到现在之间获取新消息的列表。但是,如果突然在聊天室中淹没了5条消息,这会使界面显得有些不自然。我希望每个消息在键入时都显示出来。
javascript有没有办法维持与服务器的连续连接,服务器将任何新消息推送到该连接,并且javascript将它们添加到界面中,以便它们几乎在服务器收到消息后立即出现?
我知道有一些轮询选项需要您安装一些apache模块等,但是我对sysadmin相当不满意,因此,我希望在共享主机帐户或php上安装非常简单的解决方案/ mysql仅解决方案。
我使用了这本书/教程来编写我的聊天应用程序:
AJAX和PHP:构建响应式Web应用程序:第5章:AJAX聊天和JSON。
它显示了如何从头开始编写完整的聊天脚本。
您还可以将 Comet与PHP结合使用。
来自:zeitoun:
Comet使Web服务器可以将数据发送到客户端,而无需客户端请求。因此,与传统的AJAX相比,该技术将产生更多的响应应用程序。在经典的AJAX应用程序中,无法实时通知Web浏览器(客户端)服务器数据模型已更改。用户必须创建一个请求(例如,通过单击链接),或者必须进行定期的AJAX请求,才能从服务器获取新数据。
我将向您展示两种使用PHP实现Comet的方法。例如:
<iframe>
第一个在客户端实时显示服务器日期,并显示一个迷你聊天窗口。
你需要:
backend.php
index.html
后端脚本(backend.php)将进行无限循环,并且只要连接了客户端,就会返回服务器时间。
<?php header("Cache-Control: no-cache, must-revalidate"); header("Expires: Sun, 5 Mar 2012 05:00:00 GMT"); flush(); ?> <!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"> <head> <title>Comet php backend</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> </head> <body> <script type="text/javascript"> // KHTML browser don't share javascripts between iframes var is_khtml = navigator.appName.match("Konqueror") || navigator.appVersion.match("KHTML"); if (is_khtml) { var prototypejs = document.createElement('script'); prototypejs.setAttribute('type','text/javascript'); prototypejs.setAttribute('src','prototype.js'); var head = document.getElementsByTagName('head'); head[0].appendChild(prototypejs); } // load the comet object var comet = window.parent.comet; </script> <?php while(1) { echo '<script type="text/javascript">'; echo 'comet.printServerTime('.time().');'; echo '</script>'; flush(); // used to send the echoed data to the client sleep(1); // a little break to unload the server CPU } ?> </body> </html>
前端脚本(index.html)创建一个“comet”javascript对象,该对象将把后端脚本连接到时间容器标签。
<!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"> <head> <title>Comet demo</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="prototype.js"></script> </head> <body> <div id="content">The server time will be shown here</div> <script type="text/javascript"> var comet = { connection : false, iframediv : false, initialize: function() { if (navigator.appVersion.indexOf("MSIE") != -1) { // For IE browsers comet.connection = new ActiveXObject("htmlfile"); comet.connection.open(); comet.connection.write("<html>"); comet.connection.write("<script>document.domain = '"+document.domain+"'"); comet.connection.write("</html>"); comet.connection.close(); comet.iframediv = comet.connection.createElement("div"); comet.connection.appendChild(comet.iframediv); comet.connection.parentWindow.comet = comet; comet.iframediv.innerHTML = "<iframe id='comet_iframe' src='./backend.php'></iframe>"; } else if (navigator.appVersion.indexOf("KHTML") != -1) { // for KHTML browsers comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id', 'comet_iframe'); comet.connection.setAttribute('src', './backend.php'); with (comet.connection.style) { position = "absolute"; left = top = "-100px"; height = width = "1px"; visibility = "hidden"; } document.body.appendChild(comet.connection); } else { // For other browser (Firefox...) comet.connection = document.createElement('iframe'); comet.connection.setAttribute('id', 'comet_iframe'); with (comet.connection.style) { left = top = "-100px"; height = width = "1px"; visibility = "hidden"; display = 'none'; } comet.iframediv = document.createElement('iframe'); comet.iframediv.setAttribute('src', './backend.php'); comet.connection.appendChild(comet.iframediv); document.body.appendChild(comet.connection); } }, // this function will be called from backend.php printServerTime: function (time) { $('content').innerHTML = time; }, onUnload: function() { if (comet.connection) { comet.connection = false; // release the iframe to prevent problems with IE when reloading the page } } } Event.observe(window, "load", comet.initialize); Event.observe(window, "unload", comet.onUnload); </script> </body> </html>
您需要使用与方法1相同的方法+一个用于dataexchange的文件(data.txt)
data.txt
现在,backend.php将做两件事:
<?php $filename = dirname(__FILE__).'/data.txt'; // store new message in the file $msg = isset($_GET['msg']) ? $_GET['msg'] : ''; if ($msg != '') { file_put_contents($filename,$msg); die(); } // infinite loop until the data file is not modified $lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0; $currentmodif = filemtime($filename); while ($currentmodif <= $lastmodif) // check if the data file has been modified { usleep(10000); // sleep 10ms to unload the CPU clearstatcache(); $currentmodif = filemtime($filename); } // return a json array $response = array(); $response['msg'] = file_get_contents($filename); $response['timestamp'] = $currentmodif; echo json_encode($response); flush(); ?>
<?php $filename = dirname(__FILE__).'/data.txt'; // store new message in the file $msg = isset($_GET['msg']) ? $_GET['msg'] : ''; if ($msg != '') { file_put_contents($filename,$msg); die(); } // infinite loop until the data file is not modified $lastmodif = isset($_GET['timestamp']) ? $_GET['timestamp'] : 0; $currentmodif = filemtime($filename); while ($currentmodif <= $lastmodif) // check if the data file has been
modified { usleep(10000); // sleep 10ms to unload the CPU clearstatcache(); $currentmodif = filemtime($filename); }
// return a json array $response = array(); $response['msg'] = file_get_contents($filename); $response['timestamp'] = $currentmodif; echo json_encode($response); flush(); ?>
前端脚本(index.html)创建<div id="content"></div>标签hat,其中将包含来自“ data.txt”文件的聊天消息,最后,它创建一个“ comet” javascript对象,该对象将调用后端脚本以监视新的聊天消息。
<div id="content"></div>
每当接收到新消息以及每次发布新消息时,彗星对象都会发送AJAX请求。持久连接仅用于监视新消息。timestampurl参数用于标识最后请求的消息,以便服务器仅在“ data.txt”时间戳比客户端时间戳新时才返回。
<!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"> <head> <title>Comet demo</title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <script type="text/javascript" src="prototype.js"></script> </head> <body> <div id="content"> </div> <p> <form action="" method="get" onsubmit="comet.doRequest($('word').value);$('word').value='';return false;"> <input type="text" name="word" id="word" value="" /> <input type="submit" name="submit" value="Send" /> </form> </p> <script type="text/javascript"> var Comet = Class.create(); Comet.prototype = { timestamp: 0, url: './backend.php', noerror: true, initialize: function() { }, connect: function() { this.ajax = new Ajax.Request(this.url, { method: 'get', parameters: { 'timestamp' : this.timestamp }, onSuccess: function(transport) { // handle the server response var response = transport.responseText.evalJSON(); this.comet.timestamp = response['timestamp']; this.comet.handleResponse(response); this.comet.noerror = true; }, onComplete: function(transport) { // send a new ajax request when this request is finished if (!this.comet.noerror) // if a connection problem occurs, try to reconnect each 5 seconds setTimeout(function(){ comet.connect() }, 5000); else this.comet.connect(); this.comet.noerror = false; } }); this.ajax.comet = this; }, disconnect: function() { }, handleResponse: function(response) { $('content').innerHTML += '<div>' + response['msg'] + '</div>'; }, doRequest: function(request) { new Ajax.Request(this.url, { method: 'get', parameters: { 'msg' : request }); } } var comet = new Comet(); comet.connect(); </script> </body> </html>
您还可以查看其他聊天应用程序,看看它们是如何做到的:
http://hot-things.net/?q=blite-BlaB!Lite是基于AJAX的,可以在支持MySQL,SQLite和PostgreSQL数据库的任何浏览器聊天系统中获得最佳查看。
Gmail / Facebook样式jQuery聊天 -此jQuery聊天模块使您可以将Gmail / Facebook样式的聊天无缝集成到现有网站中。
编写JavaScript / PHP聊天服务器 -教程
CometChat -CometChat在标准共享服务器上运行。只需要PHP + mySQL。