传统AJAX技术
JavaScript 调用 XMLHttpRequest 对象发出 HTTP 请求,JavaScript 响应处理函数根据服务器返回的信息对 HTML 页面的显示进行更新。
使用 AJAX 实现“服务器推”与传统的 AJAX 应用不同之处在于:
- 服务器端会阻塞请求直到有数据传递或超时才返回。
- 客户端 JavaScript 响应处理函数会在处理完服务器返回的信息后,再次发出请求,重新建立连接。
- 当客户端处理接收的数据、重新建立连接时,服务器端可能有新的数据到达;这些信息会被服务器端保存直到客户端重新建立连接,客户端会一次把当前服务器端所有的信息取。
以上来自IDM DW
理解起来可能很费劲,我做了一下总结,相对比较容易理解。
做了一个简单的及时通讯程序,总结一下各方面。
首先我选用的是ExtJs框架,这个框架无所谓,什么框架都行,但是你要知道你用框架干什么了,其实很简单,就是实现ajax交互,用ajax想后台发送请求。
那么怎么做到长连接:
传统的轮询:
首先客户端定时向服务器发送请求询问服务器有没有新消息,服务器得到新消息之后马上返回消息。
客户端得到消息,刷新(注意不是全页面刷新,而是ajax动态写入HTML元素让页面局部刷新(ajax=页面局部刷新技术))
上面的方法打个比方就是你定时让一个人去考察市场,然后考察完毕马上回来,你来做相应的处理。结果是你不能在市场发生变更的第一时间得到市场消息。
长连接方式:
页面加载的时候向服务器发送请求,询问是否有新消息。
服务器查询最新消息,进行判断:
如果有新消息,发送到客户端。
如果没有最新消息,阻塞连接。
页面得到消息之后刷新到页面,然后马上继续与服务器建立连接(长连接更应该说是与服务器建立连接)。
这个方法就好像,你安排一个人在市场,让他在市场发生变化的时候马上回来通知你,然后马上回去继续考察。
下面是我用Ext+PHP自己做的例子,算是一个入门。
Ext版本:4.0
定义类ChatWin
1 Ext.define('Leaves.im.ChatWin', { 2 extend : 'Ext.window.Window', 3 timestamp : 0, 4 mainWindow : null, 5 6 initComponent : function() { 7 this.createWindow(this); 8 }, 9 10 createWindow : function(me) { 11 me.display = Ext.create('Ext.container.Container', { 12 width : '100%', 13 height : 200, 14 html:'' 15 }); 16 17 var editor = Ext.create('Ext.form.field.HtmlEditor', { 18 xtype : 'htmleditor', 19 enableColors : false, 20 enableAlignments : false, 21 width : '100%' 22 }); 23 24 var mainPanel = Ext.create('Ext.panel.Panel', { 25 frame : true, 26 height : '100%', 27 width : '100%', 28 layout : 'vbox', 29 items : [ me.display, editor ], 30 buttons : [ { 31 text : '发送', 32 handler : function() { 33 me.sendMessage(editor.getValue()); 34 editor.setValue(); 35 editor.focus(); 36 } 37 } ] 38 }); 39 40 me.mainWindow = Ext.create('Ext.window.Window', { 41 title : '聊天室', 42 height : 500, 43 width : 600, 44 layout : 'fit', 45 items : [ mainPanel ] 46 }); 47 }, 48 49 /** 50 * 获取消息 timestamp 最后一次获取消息时间 51 */ 52 getMessage : function(timestamp) { 53 var me = this; 54 Ext.Ajax.request({ 55 url : 'comet.php', 56 success : function(response) { 57 var text = response.responseText; 58 var jsonObj = Ext.JSON.decode(text); 59 60 me.display.update(me.display.html+jsonObj.msg+'
',true); 61 62 63 timestamp = jsonObj.timestamp; 64 me.getMessage(jsonObj.timestamp); 65 }, 66 failure : function(response) { 67 var text = response.responseText; 68 var jsonObj = Ext.JSON.decode(text); 69 me.getMessage(jsonObj.timestamp); 70 }, 71 params : { 72 timestamp : timestamp 73 } 74 }); 75 }, 76 /** 77 * 发送消息 message 要发送的消息 78 */ 79 sendMessage : function(message) { 80 Ext.Ajax.request({ 81 url : 'comet.php', 82 params : { 83 msg : message 84 } 85 }); 86 }, 87 88 showChatWin : function(y, x, title) { 89 this.mainWindow.title = title; 90 this.mainWindow.y = y; 91 this.mainWindow.x = x; 92 this.getMessage(this.timestamp); 93 this.mainWindow.show(); 94 } 95 }, function() { 96 Ext.Ajax.timeout = 900000; 97 });
启动类comet.js
1 Ext.Loader.setConfig({ 2 enabled : true, 3 paths : { 4 'Leaves.im.ChatWin' : 'ChatWin.js' 5 } 6 }); 7 Ext.onReady(function() { 8 var charWin = Ext.create('Leaves.im.ChatWin'); 9 charWin.showChatWin(100,100,'我的聊天框'); 10 });
主页面
1 DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 2 <html> 3 <head> 4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 5 <title>Comet demotitle> 6 <link href="../ExtJs/resources/css/ext-all.css" rel="stylesheet" 7 type="text/css"> 8 <script type="text/javascript" src="../ExtJs/ext-all-debug.js">script> 9 <script type="text/javascript" src="comet.js">script> 10 head> 11 <body> 12 13 body> 14 html>
服务器PHP脚本
1 php 2 $filename = dirname ( __FILE__ ) . '/data.txt'; 3 $msg = isset ( $_POST ['msg'] ) ? $_POST ['msg'] : ''; 4 5 if ($msg != '') { 6 file_put_contents ( $filename, $msg ); 7 die (); 8 } 9 10 set_time_limit ( 0 ); 11 $lastmodif = isset ( $_POST ['timestamp'] ) ? $_POST ['timestamp'] : 0; 12 // 取得文件最后修改时间 13 $currentmodif = filemtime ( $filename ); 14 15 while ( $currentmodif <= $lastmodif ) { 16 // 有释放CPU占用率的作用 17 usleep ( 100000 ); 18 // 清除文件缓存信息 19 clearstatcache (); 20 $currentmodif = filemtime ( $filename ); 21 } 22 23 $response = array (); 24 $response ['msg'] = file_get_contents ( $filename ); 25 $response ['timestamp'] = $currentmodif; 26 echo json_encode ( $response ); 27 ob_flush (); 28 flush (); 29 ?>