网页实时聊天之js和jQuery实现ajax长轮询

众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系。所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息。

一直以来的方式无非有这么几种:

1、长连接,即服务器端不断开联系,PHP服务器端用ob系列函数来不停的读取输出,但是相当耗费服务器资源。

2、Flash socket,flash的as3语言,创建一个socket服务器用来处理信息。

3、轮询,顾名思义就是不停地发送查询消息,一有新消息立刻更新,但是会有多次无用请求。

4、长轮询,是轮询的升级版,需要服务器端的配合。

5、websocket,HTML5的通信功能,建立一个与服务器端的专用接口ws协议来进行通讯,兼容可能成为问题,改天研究一下这个。

这篇博文总结一下用JS和JQ两种方式(其实不同就是js和jq的实现),实现AJAX长轮询。


长轮询的思想:

如图:用AJAX发送询问信息,服务器在没有信息要返回的时候进入无限等待。由于AJAX异步的特性,PHP在服务器端执行等待不会影响到页面的正常处理。一旦服务器查询到返回信息,服务器返回信息,AJAX用回调函数处理这条信息,同时迅速再次发送一个请求等待服务器处理。

与传统轮询相比,长轮询在服务器没的返回信息的时候进入等待,减少了普通轮询服务器无数次的空回复。可以这样认为,长轮询使服务器每次的返回更有目的性,而不是盲目返回。


长轮询的服务器端实现:

聊天信息存储:

数据库设计为信息ID(msgid),发送人(sender),接收人(receiver),信息内容(content),设置senderRead和receiverRead的目的是标记信息是否已被读取,读取后改变标记,以区别信息是否已经被读取。

  1. create table msg{
  2.  
  3.   msgid int not null primary key auto_increment,
  4.  
  5.   sender char(16) not null,
  6.  
  7.   receiver char(16) not null,
  8.  
  9.   content text, //信息内容用text类型,存储量可达到65535字符
  10.  
  11.   senderRead tinyint enum(0,1) default 0,
  12.  
  13.   receiverRead tinyint enum(0,1) default 0 //设置一个是否已读的flag标记
  14.  
  15. }

PHP脚本:

脚本的主要目的是处理来自ajax的每次询问,ajax每次询问就查询一下数据库,看有没有新的信息,如果没有,刚用usleep()函数等待一秒后再次查询,直到有新信息插入数据库并被查到,脚本返回查询到的数据,并退出无限循环,结束脚本。

  1. set_time_limit(0);//设置脚本超时时间为无限,不然在过了超时时间后脚本会自动关闭,轮询失败。
  2.  
  3. $link=new mysqli("host","user","password","database");
  4.  
  5. $search="select sender,receiver,content from msg where receiverRead=0 limit 1";//限制每次读出一条数据,便于修改其已读flag
  6.  
  7. $change="update chat set receiverRead=1 where receiverRead=0 limit 1";
  8.  
  9. while (true) { //进入无限循环
  10.  
  11.     $res=$link->query($sql); //查询结果
  12.  
  13.    if($res->num_rows!=0){ //当有未读信息时读取信息
  14.  
  15.       $link->query($change);//将信息的已读flag设为1
  16.  
  17.       $msg=$res->fetch_assoc();
  18.  
  19.       $jsonstr=json_encode($msg);//取到信息,将信息用转码为json格式,返回给JS
  20.  
  21.       echo $jsonstr;
  22.  
  23.       break;//输出信息后退出while循环,结束当前脚本
  24.  
  25.     }
  26.  
  27.   usleep(1000);//如果没有信息不会进入if块,但会执行一下等待1秒,防止PHP因循环假死。
  28.  
  29. }


客户端实现:

客户端的主要任务是设置一个ajax请求函数,每次查询时被调用,当没有信息返回时,服务器端被搁置,当前页面正常执行;当有信息返回时,函数处理返回的数据,并迅速再次调用此函数发送一次请求。

用原生JS:

  1. function link(){
  2.  
  3. var xhr=null;//先设置xhr为空,为了轮询时再次调用函数对xhr重用,引发错误
  4.  
  5. xhr=new XMLHttpRequest();
  6.  
  7. xhr.open('GET','serviceback.php',true);//第三个参数一定要设置为true,异步不阻塞,不会影响到后面JS的执行。
  8.  
  9. xhr.send();
  10.  
  11. xhr.onreadystatechange=function(){
  12.  
  13.     if (xhr.readyState==4) { 严密也可加使用(xhr.readyState==4 && xhr.status ==200)限定服务器响应码为200时才进行处理。
  14.  
  15.       if(xhr.responseText!=''){
  16.  
  17.         process... //服务器端返回信息,且返回信息不为空,则开始处理返回信息。
  18.  
  19.       }
  20.  
  21.   setTimeout("link()",300);

    //递归再次调用link()函数,用setTimeOut()设置延时是因为服务器端进行sql操作时会耗时,当有新信息时,在服务器将要置已读flag为1还未成功时,AJAX可能已经又发出多条查询信息了,会导致一条信息多次返回。
  22.  
  23.   }
  24.  
  25. };
  26. }

用jQuery插件实现:

  1. var link={           //jQuery的AJAX执行的配置对象
  2.  
  3. type:"GET",      //设置请求方式,默认为GET,
  4.  
  5. async:true,      //设置是否异步,默认为异步
  6.  
  7. url:"customback.php",
  8.  
  9. dataType:"json",    //设置期望的返回格式,因服务器返回json格式,这里将数据作为json格式对待
  10.  
  11. success:function (msg){
  12.  
  13.    process...
  14.  
  15.   setTimeout("link()",300);
  16.  
  17. }              //成功时的回调函数,处理返回数据,并且延时建立新的请求连接
  18.  
  19. }
  20.  
  21. $.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

[转]网页实时聊天之js和jQuery实现ajax长轮询 PHP的更多相关文章

  1. 网页实时聊天之js和jQuery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  2. php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室)

    php websocket-网页实时聊天之PHP实现websocket(ajax长轮询和websocket都可以时间网络聊天室) 一.总结 1.ajax长轮询和websocket都可以时间网络聊天室 ...

  3. Js和Jquery实现ajax长轮询

    众所周知,HTTP协议是无状态的,所以一次的请求都是一个单独的事件,和前后都没有联系.所以我们在解决网页实时聊天时就遇到一个问题,如何保证与服务器的长时间联系,从而源源不段地获取信息. 一直以来的方式 ...

  4. Comet 反Ajax: jQuery与PHP实现Ajax长轮询

    原文地址(http://justcode.ikeepstudying.com/2016/08/comet-%E5%8F%8Dajax-%E5%9F%BA%E4%BA%8Ejquery%E4%B8%8E ...

  5. 基于jquery,php实现AJAX长轮询(LongPoll),类似推送机制

    HTTP是无状态.单向的协议,用户只能够通过客服端向服务器发送请求并由服务器处理发回一个响应.若要实现聊天室.WEBQQ.在线客服.邮箱等这些即时通讯的应用,就要用到“ 服务器推送技术(Comet)” ...

  6. 网页实时聊天之PHP实现websocket

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  7. 网页实时聊天之PHP如何实现websocket

    网页实时聊天之PHP如何实现websocket 一.总结 一句话总结: 应用 PHP 的 socket 函数库:PHP 的 socket 函数库跟 C 语言的 socket 函数非常类似 PHP 实现 ...

  8. SignalR实现网页实时聊天功能

    SignalR是利用html5 sokit方式实现网页的实时性,在客户端不支持html5的情况下通过轮询实现 实现原理是客户端发送的消息先去服务器,然后服务器根据需要将消息广播到需要接收信息的客户群. ...

  9. 分享一个基于长连接+长轮询+原生的JS及AJAX实现的多人在线即时交流聊天室

    实现网页版的在线聊天室的方法有很多,在没有来到HTML5之前,常见的有:定时轮询.长连接+长轮询.基于第三方插件(如FLASH的Socket),而如果是HTML5,则比较简单,可以直接使用WebSoc ...

随机推荐

  1. c#文件比较Code

    我想我们很多时候想比较一个文件里面是否有改动,比如一个dll库是新加了一个方法或修改了其中的方法实现,不能通过可视化的工具来比较的时候,可以用这个小工具来比较, 以下是比较文件的代码. using S ...

  2. centos 7 安装 python3.6 python3 安装步骤以及pip pip3安装挂载

    首先去python官网下载python3的源码包,网址:https://www.python.org/ 或者直接wget下载 wget https://www.python.org/ftp/pytho ...

  3. max10之pll时钟源切换

    问题3:PLL切换功能中,多次切换可能造成PLL锁不定 从现象看clkbadx信号是不影响的,但locked信号一定是有影响的.

  4. TypeError: 'MongoClient' object is not callable

    在声明数据库的时候,将中括号[ ]换成了圆括号() 错误:

  5. UISegmentedControl 改变选中字体的颜色

    //设置选中的字体颜色为蓝色    [segmentControll setTitleTextAttributes:@{NSForegroundColorAttributeName:[UIColor ...

  6. js获取标签下标

    <body> <div class="titTab"> <span>低</span> <span>中</span& ...

  7. hdu 5099 简单模拟(比较型号)

    http://acm.hdu.edu.cn/showproblem.php?pid=5099 比较两个安卓手机型号,水题 注意点:A is actually implicit and usually ...

  8. js获取元素下标

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

  9. file新建文件及文件夹

    1.获取包名的根目录:mRootPath = getFilesDir().getParent(); // ====mRootPath===/data/data/com.yoyu.file  获取SD卡 ...

  10. EBS 多sheet页Excel动态报表开发过程

    http://zhangzhongjie.iteye.com/blog/1779891 .前言本文讲述的多Sheet页EXCEL报表开发方式和开发HTML,PDF这类报表的方法大致是一致的,唯一不同的 ...