利用缓存、长连接实现文字直播

要求:

  • 有并发需要
  • 用户需要得到增量数据
  • 后台仅一个输入框

由于需要消息及时到达客户端,所以需要JS轮询或者长连接。用户打开网页会看到历史消息,然后执行长连接请求,获取后台增量数据。数据应部署在缓存集群当中。 思路,将发送的文字播报依照当前频道作为key存贮在memcached中,是一个数组,而每一次新增播报都append到数组末尾,每个消息包含消息内容和创建时间,还需要单独存贮一个该频道最后消息的时间。 用户第一次访问页面,将该频道中的全部内容返回给用户,然后执行长连接请求。 长连接请求中包含用户获得的最后消息的时间,服务器通过该时间和已存贮的最终时间判断当前用户获得的是否是最后一条消息,如果不是,则返回频道缓存数据当中用户还未获得的消息。 代码:

<?php
/**
 * @author Abel
 * email:abel.zhou@hotmail.com
 * 2014-02-14
 * UTF-8
 */
class IndexController extends MainController {

	/**
	 * (non-PHPdoc)
	 *
	 * @see CController::init()
	 */
	public function init() {
	}

	public function actionIndex() {
		$this->render('test');
	}

	/**
	 * 获得新数据长连接频道
	 */
	public function actionLong (){
		//获得该用户获得的最后的消息时间
		$last_content_time = $this->_request->getParam('last_time');
		while(1){
			//根据contents最后发表的时间与当前获得的最后消息时间进行比对
			$last_time = Zii::app()->cache->get('contents_time');
			//如果当前消息为最新消息则休眠1秒后执行下一次循环
			if($last_content_time == $last_time){
				sleep(1);continue;
			}
			//取出全部的contents频道的消息
			$contents = Zii::app()->cache->get('contents');
			//从后往前查找用户没有获取到的消息 依次倒叙追加到返回消息中
			$return_contents = array();
			for($i=count($contents)-1;$i>0;$i--){
				if($contents[$i]['time']==$last_time){
					break;
				}
				 array_unshift($return_contents, $contents[$i]);
			}
			//返回数据
			if(!empty($return_contents)){
				$this->_helper->returnJson(200, 'success',$return_contents);
			}
		}
	}

	/**
	 * 获得历史消息
	 */
	public function actionGetold(){
		//从缓存当中读取全部已经发出的消息
		$all_content = Zii::app()->cache->get('contents');
		//如果contents频道直播还未开始则返回空
		if(empty($all_content)){
			$this->_helper->returnJson(400, 'none', array());
		}
		//返回contents频道直播全部消息
		$this->_helper->returnJson(200, 'success', $all_content);
	}

	/**
	 * 添加content 到 contents频道
	 */
	public function actionSetname(){
		$content = $this->_request->getParam('content');
		$last_time = time();
		$content = array('content'=>$content,'time'=>$last_time);
		$all_content = Zii::app()->cache->get('contents');
		if(empty($all_content)){
			Zii::app()->cache->set('contents', array($content));
		}else{
			array_push($all_content, $content);
			Zii::app()->cache->set('contents', $all_content);
		}
		//contents频道最后发表的消息时间
		Zii::app()->cache->set('contents_time', $last_time);
		var_dump($all_content);exit;
	}
}

页面代码:

<div id='msg'>
</div>
<script>
var last_time=0;
//加载历史消息
$(document).ready(function(){
	$.ajax({
		type : 'post',
		url : '/index/getold',
		data : {
		},
		success : function(res) {
			if(res.code == 400){
				$('#msg').append('<br/>暂无数据');
			}
			if (res.code == 200) {
				show_content(res.data);
			}
		}
	}); 
	test(); 
});

function test(){
	$.ajax({
		type : 'post',
		url : '/index/long',
		timeout:10000,
		data : { 'last_time':last_time},
		success : function(res) {
			if (res.code == 200) {
				show_content(res.data);
				test();
			}
		},
		error:function(XMLHttpRequest,textStatus,errorThrown){
			if(textStatus == 'timeout'){
				test();
			}
		}
	});
};

function show_content(data){
	for(var i=0;i<data.length;i++){
		$('#msg').append('<br/><span>'+data[i].content+'</span>');
		last_time = data[i].time;
	}
}

</script>

Categories:

Updated: