• 沙里软件

  • ShaliSoft.com [手机站]   办公桌收纳抽屉
  • 首页
  • 博文
  • 演示
  • 管理
  • 服务器推技术简介及php实现服务器推技术的聊天室

    网络   2013/9/24 11:48:00

    IBM:Comet:基于 HTTP 长连接的“服务器推”技术

    DEMO1:

      首先是首页,包含一个文本输入和一个显示聊天内容的iframe,还有一个隐藏iframe用来提交form表单:

    <?php

    //chat.php

    header('cache-control: private');

    header('Content-Type: text/html; charset=utf-8');

    ?>

    <html>

    <script type="text/javascript">

    function submitChat(obj) {

    obj.submit();

    document.getElementsByName('content')[0].value = '';

    }

    </script>

    <iframe src="./chat_content.php" height="300" width="100%"></iframe>

    <iframe name="say" height="0" width="0"></iframe>

    <form method="POST" target="say" action="./say.php" onsubmit="submitChat(this)">

    <input type="text" size="30" name="content" /> <input type="button" value="say"onclick="submitChat(this.form)" />

    </form>

    </html>

      另外一个就是保存用户提交的聊天内容了,我简单的写一下文本,而且没有做什么锁定,这个只是简易版本:

    <?php

    $content = trim($_POST['content']);

    if ($content) {

    $fp = fopen('./chat.txt', 'a');

    fwrite($fp, $content . "\n");

    fclose($fp);

    clearstatcache();

    }

    ?>

      接下来看主要的HTTP长连接部分,也就是chat_content.php文件:

    <?php

    header('cache-control: private');

    header('Content-Type: text/html; charset=utf-8');


    //测试设置30秒超时,一般会设置比较长时间。

    set_time_limit(30);


    //这一行是为了搞定IE这个BT

    echo str_repeat(' ', 256);


    ob_flush();

    flush();

    $fp = new SplFileObject('./chat.txt', 'r+');

    $line = 0;

    $totalLine = 0;

    while (!$fp->eof()) {

    $fp->current();

    $totalLine++;

    $fp->next();

    }

    $fp->seek($totalLine);

    $i = $totalLine - 1;

    while (true) {

    if (!$fp->eof()) {

    if ($content = trim($fp->current())) {

    echo '<div>';

    echo htmlspecialchars($content);

    echo "</div>";

    flush();

    $fp->next();

    $i++;

    }

    } else {

    $fp->seek($i - 1);

    $fp->next();

    }


    {

    //这里可以添加心跳检测后退出循环

    }

    usleep(1000);

    }

    ?>

      06. 设置一个超时时间,由于要保持HTTP长连接,这个时间肯定要比较长,可能要几个小时吧,上面提到的文章里也有说明,这种HTTP长连接只能打开两个,由于浏览器的限制。另外其实即使你设置了一个永不超时,其实上服务器部分(如Apache)的配置文件也可能对HTTP请求设置了最长等待时间,所以也可能效果会不是你想的,一般默认可能都是15分钟超时。如果有兴趣可以自己尝试修改。

      09. 这里输出了一段空白,主要是手册上已经说明了,IE浏览器在前面256个字符是不会直接输出的,所以我们先随便输出些空白,以便让后面的内容输出来,可能其他浏览器也有其他浏览器的设置,具体可以查看PHP手册的frush函数的说明。接下去11、12行就是强制把这些空白符丢给浏览器输出。

      13. ~ 20. 这里主要是为了计算文件行数,以便从这一行后面开始读内容。

      接下去的while循环就是一个死循环了,就是循环输出文件内容,每次判断是否到达文件末尾,如果有用户写入文件,则当前检测肯定不是文件末尾,就将该行读取出来输出,否则将指针往前移动一行,继续循环,每次等待1000微秒,

      39. 如果一直保持长连接,那么即使客户端断开,服务端也不一定能知道客户端已经断开,所以这里可能还需要做一些心跳记录,比如每个用户保持一个心跳flag,每格几秒更新一下最后心跳时间,当检测最后时间很久没更新后,推出这个死循环,关闭这个HTTP连接。



    DEMO2:


    传统的B/S结构的应用程序,都是采用\"客户端拉\"结束来实现客户端和服务器端的数据交换。

    本文将通过结合Ticks,来实现一个服务器推的PHP聊天室简单构想。


    PHPer,尤其是用过set_cookie, header的,一定见过这样的提示信息:\"Warning: Cannot modify header information - headers already sent by.....\", 这是因为通过HTTP协议通信,数据包会包含俩个部分,一个是Header,一个是data。一般来说,都是先Header部分,在Heaer部分指明了Data部分的长度,然后使用\\r\\n\\r\\n来表示header部分结束,接下来是Data部分。


    当我们有任何输出的时候,Header部分就发送了,这个时候,你再想header函数来改变一些Header部分的域信息,就会得到上面的提示信息。


    一个简单的办法就是使用output_buffering。让它来缓存服务器的输出,不要太早将Header部分发给客户端。


    那么,如果不使用output_buffering,是不是就可以实现,每当服务器有输出,就立即发送给客户端呢?


    做个如下试验://设置php.ini中output_buffering=0 或者使用ob_end_flush()关闭缓存


    set_time_limit(0);

    for($i=0;$i<10;$i++){

     echo \"Now Index is :\". $i;

     sleep(1);

    }

     结果我们发现,还是要等到脚本全部执行完以后,才能一次看到所有的结果。。

     为什么呢?

     这是因为我们只是解决了缓存问题,但是还有一个缓冲问题,PHP会缓冲程序的输出。所以,这个时候,我们还需要调用,flush(), 来强制使得PHP将所有的程序输出发送给客户端。//设置php.ini中output_buffering=0

    ob_end_flush();//关闭缓存


    set_time_limit(0);

    for($i=0;$i<10;$i++){

     echo \"Now Index is :\". $i;

     flush();

     sleep(1);

    }

       现在是不是看到了,不断有服务器的数据显示出来?


       有几个概念之间的关系,我这里补充以下:

       在代码中使用ob_start(), 就相当于在php.ini中使用output_buffering=on一样,使用服务器缓存。

       在代码中使用ob_end_flush() 就相当于在php.ini中使用output_buffering = false一样,关闭服务器缓存。


        基于前面的讨论,我们就有可能使用Ticks来实现,一个无刷新,无ajax的聊天室: 页面中包含俩个iframe,一个是不断获取聊天室的聊天内容,一个包含用户发表聊天内容的form. 这样,在第一个frame的脚本中:

    ob_end_clear();//关闭缓存

    set_time_limit(0);

    ob_implicit_flush(); //这个语句将强制每当有输出就自动刷新,相当于在每个echo后,调用flush()

    $new_mesg = NULL;

    register_tick_function(\"getNewMesg\");

    declare(ticks=1){

     while(1){

        if(!is_null($new_mesg)){

             foreach($new_mesg as $msg){

                   echo $msg;

             }

             $new_mesg = null;

        }      

     }

    }


    function getNewMesg(){

    //通过查询数据库,或者共享内存,来获取现在的聊天室大厅的内容。

    //返回一个数组,包含所有的新的聊天内容

    }


    这样就实现了一个简单的使用服务器推技术的聊天室的框架。

    当然,关于实时输出,还有一些其他的限制,比如在PHP5手册中讲到的:

    个别web服务器程序,特别是Win32下的web服务器程序,在发送结果到浏览器之前,仍然会缓存脚本的输出,直到程序结束为止。


    有些Apache的模块,比如mod_gzip,可能自己进行输出缓存,这将导致flush()函数产生的结果不会立即被发送到客户端浏览器。 [Page]


    甚至浏览器也会在显示之前,缓存接收到的内容。例如 Netscape 浏览器会在接受到换行或 html 标记的开头之前缓存内容,并且在接受到 </table> 标记之前,不会显示出整个表格。


    一些版本的 Microsoft Internet Explorer 只有当接受到的256个字节以后才开始显示该页面,所以必须发送一些额外的空格来让这些浏览器显示页面内容。


    接下来,我贴一个很有趣的代码,有兴趣的同学,可以试试:

    <?php

    header('Content-type: multipart/x-mixed-replace;boundary=endofsection');

    print "endofsection";

    for( $i = 0; $i <10;$i ++ )

    {

           sleep(1);

           print "Content-type: text/plain ";

           print "Part $i ";

           print "--endofsection ";

           ob_flush(); //强制将缓存区的内容输出

           flush(); //强制将缓冲区的内容发送给客户端

     }

    print "Content-type: text plain ";

    print "The end ";

    print "--endofsection-- ";


    ?>


     使用firefox打开,看看你看到了什么。

     这个例子,使用了ob_flush(), 这样可以在代码中控制缓存区内容的输出时机,更加灵活一些。


    阅读(20606) 分享(0)

    上一篇: PHP的FTP操作函数大全
    下一篇: 优化PHP代码,使php更高效

  • 精彩推荐

    ◆ MySQL配置优化
    ◆ WINDOWS 2003 IIS6 支持SHA256。基础连接已经关闭 发送时发生错误修复
    ◆ sql2000增加序号列,自动增加列,ROW_NUMBER()
    ◆ SQL set statistics命令
    ◆ Google Analytics与百度统计的原理
    ◆ OutputCache 缓存 VaryByCustom的使用,增加缓存后手机端无法做判断的处理
    ◆ SQLSERVER数据库检查DBCC CheckDB
    ◆ 为什么mysql使用SELECT*比SELECT字段 查询速度还快
    ◆ 谷歌镜像网站大全 google翻墙地址大全
    ◆ 携程全线瘫痪,传言代码被恶意删除
  • 用心做事 不能唯利是图

    • 吊儿
    • 用QQ联系我17905772
  • 搜索


  • 最新文章

    • 导出Excel 格式 mso-number-format
    • 服务器iis支持tls1.2,windows server 2008 r2 中IIS启用TLS 1.2(安装SSL后用TLS 1.2)
    • MySQL配置优化
    • EditPlus 添加文件比较工具winmerge
    • 滚动悬浮固定JS特效

  • 热门文章

    • php sso单点登录实现代码
    • 中国菜刀(China chopper) 最新黑客工具
    • redis.conf中文版(基于2.4)
    • 搜索引擎名单大全
    • php图片上传类,支持加水印,生成略缩图

  • 最新图库


  • 最新评论


  • 友情链接

  • 沙里软件

  • 最近访客

    Powered by ShaliSoft.com 豫ICP备13008529号

    免责声明:本站部分内容来源于互联网,转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,不为其版权负责,也不构成任何其他建议。如果发现侵犯版权,联系QQ17905772进行删除。