• COMET探索系列三【异步通知服务器关闭数据连接实现思路】


    在小编络络 COMET实践笔记 一文中注意事项中有这么一段话

    使用长连接时, 存在一个很常见的场景:客户端需要关闭页 面,而服务器端还处在读取数据的阻塞状态,客户端需要及时通知服务器端关闭数据连接。服务器在收到关闭请求后首先要从读取数据的阻塞状态唤醒,然后释放为 这个客户端分配的资源,再关闭连接。所以在设计上,我们需要使客户端的控制请求和数据请求使用不同的 HTTP 连接,才能使控制请求不会被阻塞。在实现上,如果是基于 iframe 流方式的长连接,客户端页面需要使用两个 iframe,一个是控制帧,用于往服务器端发送控制请求,控制请求能很快收到响应,不会被阻塞;一个是显示帧,用于往服务器端发送长连接请求。如果是基于 AJAX 的长轮询方式,客户端可以异步地发出一个 XMLHttpRequest 请求,通知服务器端关闭数据连接。

     

    当初一直没想明白客户端要怎么样通知服务器端关闭数据连接,钻了牛角尖了,昨晚睡觉胡思乱想竟然给我想到一个方法,一大早起来就开始折腾了。

     

    大致思路:页面(index.html)打开时挂起一个长连接(backend.php),需要关闭长连接时(如刷新页面时,本实验为了直观使用按钮点击)向服务器端发送一个异步关闭请求,服务器接收到关闭请求后在服务器上创建一个 close.txt 的关闭请求标识文件,在 backend.php 中检测有没有新消息的同时检测是否存在 close.txt 文件,如果存在 close.txt 文件则不管有没有取到消息都返回,index.html 根据返回的结果判断是主否主动关闭请求,如果是主动关闭请求则不再发起长连接。

     

    实验文件:

    index.html      首页,包含长连接请求,消息发送请求,关闭请求等内容

    backend.php      后台消息获取文件,检查 data.txt 是否为空,及 close.txt 是否存在

    writedata.php     获取客户端传来的消息,并将消息写入 data.txt 中

    stop.php        接收客户端的半闭请求,并生成 close.txt 文件

     

    1. index.html

    复制代码
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
      
    <head>
        <title>Comet demo</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
        <script type="text/javascript" src="jquery.js"></script>
           
        <script>
        var comet = {
            url:'backend.php',
            error:false,
            stop:0,
            connect : function(){
                $.ajax({
                    url: comet.url,
                    type: 'post',
                    dataType: 'json',
                    timeout: 0,
                    success: function (response) {
                        comet.error = false;
                        comet.stop = response.stop ;
                        $("#content").append('<div>' + response.msg + '</div>');
                    },
    
                    error: function () {
                        comet.error = true;
                    },
    
                    complete: function () {
                        if (comet.error) {
                            setTimeout(function () {
                                comet.connect();
                            }, 5000);
                        } else {
                  // 如果是主动关闭连接则不再发起请求 comet.stop ? '': comet.connect(); } } }) } } // 发送消息 function send_msg() { var msg = $('#word').val(); $('#word').val(''); $.post('writedata.php',{'msg': msg}); return false; } // 发送关闭请求 function close_commet() { $.post('stop.php',function(res){ $("#content").append('<div>' + res + '</div>'); }) } $(document).ready(function () { //页面加载完毕创建长连接 comet.connect(); }); </script>    </head>    <body>       <div id="content"></div> <p><form> <input type="text" name="word" id="word" value=""/>        <input type="button" name="send" onclick="send_msg();" value="发送"/>    <input type="button" name="close" onclick="close_commet();" value="关闭长连接" /> </form> </p>       </body> </html>
    复制代码

     2. writedata.php

    复制代码
    <?php
    
    // 获取客户端消息,并存入 data.txt
    
    $filename = './data.txt';
    
    $msg = isset($_REQUEST['msg']) ? $_REQUEST['msg'] : '';
    
    file_put_contents($filename, $msg);
    复制代码

    3. stop.php

    复制代码
    <?php
    // 本文件用于接收到客户端异步关闭请求、
    // 接收到关闭请求时应该想办法将该关闭请求让 backend.php 获取到
    // 所以我们应该要将该关闭请求放到一个 backend.php 可以读取的空间,那么放到哪里呢
    // cookie不行:因为 cookie 是存放在客户端的,发送关闭请求的时候,长连接已经建立,是获取不到关闭请求中创建的cookie的
    // session也不行:backend.php 中由于处于阻塞状态,为了防止占用 session 我们在进入阻塞之前就关闭了 session 所以 session 也不行
    // 最适合不过的无疑是 Memcache 了,当然数据库也行,这里为了简便,我们使用文件,当收到关闭请求时在服务器创建一个 close 文件,表示要关闭长连接
    // backend.php 如果检测到存在 close 文件时不管有没有取到数据都返回
    
    file_put_contents('./close.txt', '');
    
    echo '接收到关闭请求';
    
    ?>
    复制代码

     4. backend.php

    复制代码
    <?php
    
    //不限制超时时间
    set_time_limit(0);
    
    //在开启session的应用中这个函数非常重要,防止页面因session占用阻塞
    session_write_close();
    
    //用来存放数据的文件
    $filename = 'data.txt';
    
    //读取文件内容
    $content = file_get_contents($filename);
    
    // 关断是否存在半闭请求
    $close = file_exists('./close.txt');
    
    // 如果 $content 为空,并且不存在关闭请求文件时阻塞等待
    while ($content=='' && !$close)
    {
        sleep(1);
        $content = file_get_contents($filename);
        $close = file_exists('./close.txt');
    }
    
    if ($close) {
        $content = '长连接已关闭';
        // 删除关闭请求标识文件
        unlink('close.txt');
        $response['stop'] = 1;
    } else {
        //清空data.txt
        file_put_contents($filename, '');
        $response['stop'] = 0;
    }
    
    
    // 返回消息
    $response['msg'] = $content;
    echo json_encode($response);
    
    ?>
    复制代码

    点击发送按钮之后:

    点击关闭长连接之后:

    相关代码下载:http://yun.baidu.com/s/1c0ovV6w

     

  • 相关阅读:
    python cook 整理
    Ajax
    跨站请求伪造 CSRF
    tornado web
    python hashable
    扩大了一个逻辑卷,resize2fs 保错:没有这个超级块
    linux重启后进入了救援模式,无法远程登录
    如何安装JDK以及配置win10的环境变量
    输出菱形
    6.28作业(2.使用3种方式求100以内偶数和)
  • 原文地址:https://www.cnblogs.com/shenming/p/4205998.html
Copyright © 2020-2023  润新知