Js和Jquery實現ajax長輪詢

衆所周知,HTTP協議是無狀態的,因此一次的請求都是一個單獨的事件,和先後都沒有聯繫。因此咱們在解決網頁實時聊天時就遇到一個問題,如何保證與服務器的長時間聯繫,從而源源不段地獲取信息。php

一直以來的方式無非有這麼幾種:html

一、長鏈接,即服務器端不斷開聯繫,PHP服務器端用ob系列函數來不停的讀取輸出,可是至關耗費服務器資源。mysql

二、Flash socket,flash的as3語言,建立一個socket服務器用來處理信息。web

三、輪詢,顧名思義就是不停地發送查詢消息,一有新消息馬上更新,可是會有屢次無用請求。ajax

四、長輪詢,是輪詢的升級版,須要服務器端的配合。sql

五、websocket,HTML5的通訊功能,創建一個與服務器端的專用接口ws協議來進行通信,兼容可能成爲問題,改天研究一下這個。數據庫

 

如圖:用AJAX發送詢問信息,服務器在沒有信息要返回的時候進入無限等待。因爲AJAX異步的特性,PHP在服務器端執行等待不會影響到頁面的正常處理。一旦服務器查詢到返回信息,服務器返回信息,AJAX用回調函數處理這條信息,同時迅速再次發送一個請求等待服務器處理。json

與傳統輪詢相比,長輪詢在服務器沒的返回信息的時候進入等待,減小了普通輪詢服務器無數次的空回覆。能夠這樣認爲,長輪詢使服務器每次的返回更有目的性,而不是盲目返回。服務器

 

長輪詢的服務器端實現:websocket

聊天信息存儲:

數據庫設計爲信息ID(msgid),發送人(sender),接收人(receiver),信息內容(content),設置senderRead和receiverRead的目的是標記信息是否已被讀取,讀取後改變標記,以區別信息是否已經被讀取。

CREATE TABLE `msg` (
  `msgid` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `sender` char(16) NOT NULL,
  `receiver` char(16) NOT NULL,
  `content` text,
  `senderRead` tinyint(1) DEFAULT '0',
  `receiverRead` tinyint(1) DEFAULT '0',
  PRIMARY KEY (`msgid`)
) ENGINE=MyISAM AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

PHP腳本:

 腳本的主要目的是處理來自ajax的每次詢問,ajax每次詢問就查詢一下數據庫,看有沒有新的信息,若是沒有,剛用usleep()函數等待一秒後再次查詢,直到有新信息插入數據庫並被查到,腳本返回查詢到的數據,並退出無限循環,結束腳本。

<?php 

set_time_limit(0);//設置腳本超時時間爲無限,否則在過了超時時間後腳本會自動關閉,輪詢失敗。

$link=new mysqli("127.0.0.1","root","root","test");

$search="select sender,receiver,content from msg where receiverRead=0 limit 1";//限制每次讀出一條數據,便於修改其已讀flag

$change="update msg set receiverRead=1 where receiverRead=0 limit 1";

while (true) {//進入無限循環

	$res = null;

	$res=$link->query($search);

	if($res->num_rows!=0){

		$link->query($change);

		$msg=$res->fetch_assoc();

		$jsonstr=json_encode($msg);

		echo $jsonstr;

		break;
	}
	usleep(1000);//若是沒有信息不會進入if塊,但會執行一下等待1秒,防止PHP因循環假死。
}

?>

客戶端實現:

客戶端的主要任務是設置一個ajax請求函數,每次查詢時被調用,當沒有信息返回時,服務器端被擱置,當前頁面正常執行;當有信息返回時,函數處理返回的數據,並迅速再次調用此函數發送一次請求。

用原生JS:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>	</title>
</head>
<body>

</body>
<script>
	function link(){

	    var xhr=null;//先設置xhr爲空,爲了輪詢時再次調用函數對xhr重用,引起錯誤

	    xhr=new XMLHttpRequest();

	    xhr.open('GET','server.php',true);//第三個參數必定要設置爲true,異步不阻塞,不會影響到後面JS的執行。

	    xhr.send();

	    xhr.onreadystatechange=function(){

	    	if(xhr.readyState==4 && xhr.status==200){

	    		var obj = JSON.parse(xhr.responseText)

	    		console.log('發送人:'+obj.sender+'接收人:'+obj.receiver+'內容:'+obj.content)

	    		setTimeout(function(){link()},3000)
	    	}
	    };
	}
	link();
</script>
</html>
相關文章
相關標籤/搜索