1.演示ServerPush服务器推送消息给浏览器端的功能
2.要明白,对http协议来讲,是不可能服务器给给浏览器主动发送信息的,因为不能满足,“请求---》响应”的机制
3.这里主要是使用的一个“长链接”的机制,模拟--》》》“服务器推送消息”(。。。我的理解:就是让浏览器不断的向服务器发送请求。。。服务器收到请求后,响应,就是长链接)
1.新建一个ServerPushChat.ashx一般处理程序。
1.修改ContentType为application/json。
2.获取请求的对象。Request。设置变量名 为me。
3.设置一个死循环,死循环中,内容:
1.根据从请求报文中获取的我是谁---》me,根据me这个变量名字到数据库中查询是否有这个变量名字的消息。
2.没有就继续下一轮的循环。
3.否则,数据库中的行数不是零了。就读出每个列的数据,序列化为json发送到浏览器端。同时删除这条数据(因为对方已经收到了。这个消息,所以就删除这条消息了),同时结束循环。break或者return;
4.在浏览器重输入ServerPushChat.ashx,打开开发者工具,可以看见ServerPushChat.ashx的状态时是pending,-->说明是在等待着服务器的响应信息。(暴露问题:while死循环一直在,所以CPU占用太高。解决方案:在下一轮循环之前,加上一个Thread.Sleep(500)毫秒;
2.新建一个ServerPushChat.html页面
1.这里没有考虑安全性问题。(用户验证)
2.设置点击“登录”后,向服务器端ServerPushChat.ashx索要信息。
3.设置点击“发送”后,向服务器端ServerPushChat.ashx请求报文,内容如下:
1.我是谁;
2.消息发给谁;
3.消息内容;
4.ServerPushChat.ashx接受到这三个变量,进行插入(这里没有做用户名,消息非空验证,)插入成功后,向浏览器端发送,json序列的“ok”;
4.接着对“发送”按钮的点击事件,写ajax
5.从ServerPushChat.ashx获取是成功的发送了--》ok,还是没有发送成功。---》显示消息不识别
6.清除发送框中的内容。
7.接着对“登录”按钮的点击事件,写ajax
1.由于请求的都是ServerPushChat.ashx这个一般处理程序。所以要使用action进行识别,到底是“登录”点击事件,还是“发送”点击事件。
2.成功从服务器端接收到了,将收到的消息,显示在ul的列表中。
3.接受成功后,接着继续,请求ServerPushChat.ashx
1.这里需要封转一个function,封装的内容,是接收成功后和接受失败后都继续该function。(类似递归,自己调用自己)
4.设置“登录”按钮为不可用状态,免得用户重复点击
1.$(this).attr("disabled","disabled");
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<title>聊天室</title>
<script src="jquery.min.js"></script>
<script type="text/javascript">
//抽出来的一个function,用于接受消息
var recv = function () {
var me = $("#me").val();
$.ajax({ //登录成功后只是接收了一次,所以这里将抽出一个单独的function
type: "post", url: "ServarPustChat.ashx",
data: { action: "receive", me: $("#me").val() },
success: function (data) {
$("#ulMsg").append($("<li>" + data.FromUserName + "对我说:" + data.Msg + "</li>"));
recv();//接收成功后仍然请求
},
error: function () {
recv();//接收失败后任然请求(原因是网路的暂时故障)
}
});
};
$(function () {
//1.发送消息,此处发现都是请求的ServarPustChat.ashx,使用action进行区分
$("#btnSend").click(function () {
$.ajax({
type: "post", url: "ServarPustChat.ashx",
//2.发送点击事件 我是,给谁,内容
data: { action: "send", Msg: $("#msg").val(), me: $("#me").val(), tousername: $("#toUserName").val() },
success: function (data) {
if (data.Status == "ok") {
$("#ulMsg").append($("<li>我对:" + $("#toUserName").val() + "说:" + $("#msg").val() + "</li>"));
//清空文本框
$("#msg").val("");
} else {
alert("发送错误,返回的报文不能识别");
}
},
error: function () {
alert("发送错误");
}
});
});
$("#btnLogin").click(function () {
recv();//点击上线后,就不断的发送请求,达到获得信息的目的
//设置“上线”按钮为不可用状态,免得用户重复点击
$("#btnLogin").attr("disabled","disabled");
});
/*
//登录接收消息
$("#btnLogin").click(function () {
var me = $("#me").val();
$.ajax({ //登录成功后只是接收了一次,所以这里将抽出一个单独的function
type: "post", url: "ServarPustChat.ashx",
data: { action: "receive", me: $("#me").val() },
success: function (data) {
$("#ulMsg").append($("<li>" + data.FromUserName+"对我说:"+data.Msg+"</li>"));
},
error: function () {
alert("接受消息失败");
}
});
});
*/
});
</script>
</head>
<body>
我是:<input id="me" type="text"/><input type="button" id="btnLogin" value="上线" /><br />
<br />
发送给:<input id="toUserName" type="text" />发送内容:<input id="msg" type="text" /><input type="button" id="btnSend" value="发送"/>
<br />
<ul id="ulMsg">
</ul>
</body>
</html>
<%@ WebHandler Language="C#" Class="ServarPustChat" %>
using System;
using System.Web;
using System.Data;
using Web1;
using System.Data.SqlClient;
using System.Web.Script.Serialization;
public class ServarPustChat : IHttpHandler {
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "application/json";//1.修改
//当向ServarPustChat.ashx文件进行请求信息的时候,加上请求的对象
//me=rupeng
//ServarPustChat.ashx?me=rupeng
//2.获取请求报文中的请求对象
string me = context.Request["me"];
//最后添加的部分。。。。。
string action=context.Request["action"];
if ("send"==action)
{
string tousername = context.Request["tousername"];
string msg = context.Request["Msg"];
SqlHelper.ExecuteNonQuery("insert into t_msgs(FromUserName,ToUserName,Msg) values(@FromUserName,@ToUserName,@Msg)"
, new SqlParameter("@ToUserName", tousername),
new SqlParameter("@FromUserName", me),
new SqlParameter("@Msg", msg));
context.Response.Write(new JavaScriptSerializer().Serialize(new { Status = "ok" }));
}
else if ("receive" == action)
{
//3.根据me这个变量名字到数据库中查询是否有这个变量名字的消息。
//4.此处设置一个死循环,让请求不断地查询
while (true)
{
DataTable dt = SqlHelper.ExecuteQuery("select top 1 * from T_Msgs where ToUserName=@ToUserName", new SqlParameter("@ToUserName", me));
if (dt.Rows.Count <= 0)
{
//System.Threading.Thread.Sleep(500);//避免一直在查询的问题,缓解cpu的压力
continue;//如果查询的时空的继续查询
}
else
{
DataRow row = dt.Rows[0];//取出第一行
long id = (long)row["id"];
string fromUserName = (string)row["FromUserName"];
string msg = (string)row["Msg"];
//发送完的信息删除操作
SqlHelper.ExecuteNonQuery("delete from T_Msgs where Id=@id", new SqlParameter("@id", id));
//将收到的消息发送给me
var data = new { FromUserName = fromUserName, Msg = msg };
string json = new JavaScriptSerializer().Serialize(data);
context.Response.Write(json);//(返回浏览器端)
break; //返回后结束循环
}
}
}
}
public bool IsReusable {
get {
return false;
}
}
}
ServrPush对服务器的压力还是很大的,服务器并行处理的数量有限,大型的网站有很多的优化策略,但是对客户端可以使用WebScoket(HTML5技术),在浏览器中写Socket,低版本的html中,只能用XmlHttpRequest(XHR)但是效率低,微软推出了一个框架,SignalR(当前浏览器支持html5就用WebScoket,不支持就用XHR)。