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
COMET探索系列三【异步通知服务器关闭数据连接实现思路】的更多相关文章
- COMET探索系列一【COMET实践笔记】
这几天在给公司的一个点对点聊天系统升级,之前只是使用简单的ajax轮询方式实现,每5秒钟取一次数据,延时太长,用户体验不是很好,因此打算采用服务器推送技术,故此整理了以下文档,将自己找到的一些资料及心 ...
- C# 互操作性入门系列(三):平台调用中的数据封送处理
好文章搬用工模式启动ing ..... { 文章中已经包含了原文链接 就不再次粘贴了 言明 改文章是一个系列,但只收录了2篇,原因是 够用了 } --------------------------- ...
- [转]C# 互操作性入门系列(三):平台调用中的数据封送处理
参考网址:https://www.cnblogs.com/FongLuo/p/4512738.html C#互操作系列文章: C# 互操作性入门系列(一):C#中互操作性介绍 C# 互操作性入门系列( ...
- android异步向服务器请求数据
下面就android向服务器请求数据的问题分析如下: 1.在android4.0以后的版本,主线程(UI线程)不在支持网络请求,原因大概是影响主线程,速度太慢,容易卡机,所以需要开启新的线程请求数据: ...
- zookeeper系列之异步通知模式-Watcher
1 watcher种类和事件种类 Watcher种类 1. zookeeper实例化时注入的默认Watcher 2. dataWatchers 一个Map<string Set<Watch ...
- COMET探索系列二【Ajax轮询复用模型】
写在前面:Ajax轮询相信大家都信手拈来在用,可是有这么一个问题,如果一个网站中同时有好多个地方需要用到这种轮询呢?就拿我们网站来说,有一个未读消息数提醒.还有一个时实时加载最新说说.昨天又加了一个全 ...
- java多线程系列(三)---等待通知机制
等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...
- [ 搭建Redis本地服务器实践系列三 ] :图解Redis客户端工具连接Redis服务器
上一章 [ 搭建Redis本地服务器实践系列二 ] :图解CentOS7配置Redis 介绍了Redis的初始化脚本文件及启动配置文件,并图解如何以服务的形式来启动.终止Redis服务,可以说我们的 ...
- Alamofire源码解读系列(三)之通知处理(Notification)
本篇讲解swift中通知的用法 前言 通知作为传递事件和数据的载体,在使用中是不受限制的.由于忘记移除某个通知的监听,会造成很多潜在的问题,这些问题在测试中是很难被发现的.但这不是我们这篇文章探讨的主 ...
随机推荐
- 112.限制请求的method装饰器
客户端与服务器之间最常用的两种请求方式: 1. GET请求一般是用来向服务器索取数据,但不会向服务器提交数据,不会对服务器的状态进行更改. 2.POST请求一般是用来向服务器提交数据,会对服务器的状态 ...
- 使用maven打包问题
项目打包:选择项目 右键->run as-> maven install . 项目中使用的是maven项目,将项目打包成war的时候有时候会出现 出现这种情况的时候解决步骤如下: 选择要打 ...
- csv文件——简单读操作01
转载:https://www.py.cn/spider/advanced/14381.html import csv with open('C:\\Users\\del\\Desktop\\123.c ...
- python numpy和矩阵
2.numpy数据选取 lst=[[1, 2, 3], [4, 5, 6]] np.array(lst)[:-1] Out[32]: array([[1, 2, 3]]) np.array(lst)[ ...
- java类的实例化顺序
1. 父类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行 2. 子类静态成员和静态初始化块 ,按在代码中出现的顺序依次执行 3. 父类实例成员和实例初始化块 ,按在代码中出现的顺序依次执行 4 ...
- Python笔记_第四篇_高阶编程_二次封装
1.二次封装: 二次封装其实就是对一个类或者一个方法进行二次的改造增加新的功能. 2.一个类的二次封装: 我们以一个进程为例,我们把Process这个库进行二次封装,增加一些功能,在调用. thoma ...
- Anaconda 添加清华源与恢复默认源
1.添加清华源 查看清华大学官方镜像源文档:https://mirrors.tuna.tsinghua.edu.cn/help/anaconda/ 本文基于Windows平台,首先用命令: conda ...
- 干货 | 玩转云文件存储——利用CFS实现web应用的共享访问
京东云文件服务(Cloud File Service,以下简称:CFS)是一种高可靠.可扩展.可共享访问的全托管分布式文件系统.它可在不中断应用服务的情况下,根据您对文件系统的使用,按需扩展或缩减,并 ...
- 01 语言基础+高级:1-8 File类与IO流_day10【缓冲流、转换流、序列化流】
day10[缓冲流.转换流.序列化流] 主要内容 缓冲流 转换流 序列化流 打印流 教学目标 能够使用字节缓冲流读取数据到程序 能够使用字节缓冲流写出数据到文件 能够明确字符缓冲流的作用和基本用法 能 ...
- Java之多线程窗口卖票问题(Runnable)
/** * 例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式 * 存在线程的安全问题,待解决. */class Window1 implements Runnable{ p ...