[轉]網頁實時聊天之js和jQuery實現ajax長輪詢 PHP

網頁實時聊天之js和jQuery實現ajax長輪詢

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

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

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

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

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

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

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

這篇博文總結一下用JS和JQ兩種方式(其實不一樣就是js和jq的實現),實現AJAX長輪詢。 json


長輪詢的思想: 服務器

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

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


長輪詢的服務器端實現:

聊天信息存儲:

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

複製代碼

create table msg{

  msgid int not null primary key auto_increment,

  sender char(16) not null,

  receiver char(16) not null,

  content text,     //信息內容用text類型,存儲量可達到65535字符

  senderRead tinyint enum(0,1) default 0,

  receiverRead tinyint enum(0,1) default 0    //設置一個是否已讀的flag標記

}

複製代碼

PHP腳本:

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

複製代碼

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

  $link=new mysqli("host","user","password","database");

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

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

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

      $res=$link->query($sql);  //查詢結果

        if($res->num_rows!=0){  //當有未讀信息時讀取信息

            $link->query($change);//將信息的已讀flag設爲1

            $msg=$res->fetch_assoc();

            $jsonstr=json_encode($msg);//取到信息,將信息用轉碼爲json格式,返回給JS

            echo $jsonstr;

            break;//輸出信息後退出while循環,結束當前腳本

        }

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

  }

複製代碼


客戶端實現:

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

用原生JS:

複製代碼

function link(){

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

    xhr=new XMLHttpRequest();

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

    xhr.send();

    xhr.onreadystatechange=function(){

        if (xhr.readyState==4) { 嚴密也可加使用(xhr.readyState==4 && xhr.status ==200)限定服務器響應碼爲200時才進行處理。

              if(xhr.responseText!=''){

                   process...  //服務器端返回信息,且返回信息不爲空,則開始處理返回信息。

             }

          setTimeout("link()",300);

//遞歸再次調用link()函數,用setTimeOut()設置延時是由於服務器端進行sql操做時會耗時,當有新信息時,在服務器將要置已讀flag爲1還未成功時,AJAX可能已經又發出多條查詢信息了,會致使一條信息屢次返回。   } }; }

複製代碼

用jQuery插件實現:

複製代碼

var link={            //jQuery的AJAX執行的配置對象

      type:"GET",      //設置請求方式,默認爲GET,

      async:true,      //設置是否異步,默認爲異步

      url:"customback.php",

      dataType:"json",    //設置指望的返回格式,因服務器返回json格式,這裏將數據做爲json格式對待

      success:function (msg){

            process...

            setTimeout("link()",300);

      }              //成功時的回調函數,處理返回數據,而且延時創建新的請求鏈接

}

$.ajax(link);          //執行ajax請求。

複製代碼


程序擴充:

添加發送聊天窗口:

新建一個函數用來處理ajax的POST請求,用ajax將發信人,每次發送的信息,收信人發送到服務器端,並設置一個單獨的PHP腳本處理信息,將信息插入數據庫。

須要注意的是,用JS原生實現POST請求發送信息時,要設置ajax對象的HTTP頭,模擬表單提交的操做:

xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");

聊天室消息處理:

爲了防止每次都查詢到所有信息,咱們對數據庫的查詢操做更改一下,設置idflag=0,每次查詢後,設置idflag爲查詢到的數據的id,查詢時咱們查詢比idflag大的ID,即,新添加進去的信息。

這樣,一個簡單的聊天室程序就作好了。

若是您以爲本博文對您有幫助,您能夠推薦或關注我,若是您有什麼問題,能夠在下方留言討論,謝謝。

分類: AJAX

相關文章
相關標籤/搜索