看了好多帖子一说长连接、长轮询、Comet之类的都是用的服务端的异步页面,大致如下:
protected void Page_Load(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(new BeginEventHandler(BeginAsyncOperation),new EndEventHandler(EndAsyncOperation));
}
而且每个人的异步页面的用法还都不一样。搞的我这个以前没用过异步页面的程序猿一头雾水,于是就想能不能不用异步页面实现长连接。经过一番研究还是可以的,不敢独享,拿出来大家给看看,有不到之处还望指点。
这个例子是一个群聊的demo,总共就两个页面一个登陆页,一个是聊天页,先看登陆页面:
我叉,这也太简单点。恩,没办法,本人业余时间有限,主要说长连接的事。点击登陆后台代码:
1 protected void btnLogin_Click(object sender, EventArgs e)
2 {
3 string name=txtName.Text.Trim();
4 if (string.IsNullOrEmpty(name) == false)
5 {
6 Session["name"] = name;
7 Response.Redirect("Chat.aspx");
8 }
9 }
再看重点的Chat.aspx页面:
前台:
1 <%@ Page Language="C#" AutoEventWireup="true" EnableSessionState="ReadOnly" CodeFile="Chat.aspx.cs" Inherits="Chat" %>
2
3 <!DOCTYPE html>
4
5 <html xmlns="http://www.w3.org/1999/xhtml">
6 <head>
7 <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
8 <title></title>
9 <script src="jquery-1.7.1.min.js"></script>
10 <script type="text/javascript">
11 //长轮询获取信息
12 function LongPolling() {
13 $.ajax(
14 {
15 url: "Chat.aspx",
16 type: "post",
17 data: { "action": "get" },
18 success: function (data){
19 $("#content").append(data + "<br>");
20 LongPolling();
21 },
22 error: function (xhr, info, obj) {
23 $("#content").append(info + "<br>");
24 LongPolling();
25 }
26 });
27 }
28 LongPolling();
29
30 //发送消息
31 function Send() {
32 if (!$("#msg").val())
33 {
34 alert("不能发空白哦!");
35 return;
36 }
37 $.ajax(
38 {
39 url: "Chat.aspx",
40 type: "post",
41 data: { "action": "send", "msg": $("#msg").val() },
42 success: function (data)
43 {
44 //貌似什么也不用做
45 }
46 });
47 }
48 </script>
49 </head>
50 <body>
51 <div id="content" style="width:500px; height:300px; overflow-y:auto; border:1px solid red;"></div>
52 <input type="text" id="msg" />
53 <input type="button" value="发送" onclick="Send()"/>
54 </body>
55 </html>
后台代码:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Threading;
5
6 /// <summary>
7 /// 注意:对应aspx页面必须加上EnableSessionState="ReadOnly"否则会造成请求阻塞
8 /// </summary>
9 public partial class Chat : BasePage
10 {
11 //全局静态变量:待发送的聊天信息
12 public static List<ChatObj> ChatObjList = new List<ChatObj>();
13 //全局静态变量:用户列表
14 public static List<string> UserList = new List<string>();
15
16 protected void Page_Load(object sender, EventArgs e)
17 {
18 //json返回的消息
19 string msg = string.Empty;
20 //验证是否登录了
21 if (Session["name"] == null)
22 {
23 Response.Redirect("Login.aspx");
25 }
26 //操作
27 string action = Request["action"];
28 //发送信息
29 if (action == "send")
30 {
31 if (string.IsNullOrEmpty(Request["msg"]) == false)
32 {
33 //模拟群聊 当前用户发的消息分发给在线的每一个人
34 foreach (var user in UserList)
35 {
36 ChatObjList.Add(new ChatObj()
37 {
38 From = Session["name"].ToString(),
39 To = user,
40 Message = Request["msg"],
41 SendTime = DateTime.Now
42 });
43 }
44 }
45 else
46 {
47 msg = "发送信息不能为空";
48 }
49 }
50 else if (action == "get")//获取信息
51 {
52 //这里是关键 检查是否有自己的消息,如果有则返回,没有则一直循环休眠
53 while (true)
54 {
55 ChatObj[] chatObjList = ChatObjList.AsEnumerable().Where(o => o.To == Session["name"].ToString()).ToArray();
56 if (chatObjList == null || chatObjList.Length == 0)
57 {
58 Thread.Sleep(1000);//休眠一秒
59 }
60 else
61 {
62 msg = string.Empty;
63 foreach (var item in chatObjList)
64 {
65 msg += item.From + "说:" + item.Message+"<br>";
66 ChatObjList.Remove(item);
67 }
68 break;
69 }
70 }
71 }
72 Response.Write(msg);
73
74 if (string.IsNullOrEmpty(action) == false)
75 {
76 //如果是ajax请求则终止响应,否则会输出整个页面的html
77 Response.End();
78 }
79 else
80 {
81 //首次加载则把用户加入到用户列表 不太完善主要演示longpolling
82 if (UserList.Contains(Session["name"].ToString())==false)
83 {
84 UserList.Add(Session["name"].ToString());
85 }
86 }
87 }
88 }
89
90 /// <summary>
91 /// 发送消息对象
92 /// </summary>
93 public class ChatObj
94 {
95 /// <summary>
96 /// 发送方
97 /// </summary>
98 public string From { get; set; }
99 /// <summary>
100 /// 接收方
101 /// </summary>
102 public string To { get; set; }
103 /// <summary>
104 /// 消息
105 /// </summary>
106 public string Message { get; set; }
107 /// <summary>
108 /// 发送时间
109 /// </summary>
110 public DateTime SendTime { get; set; }
111 }
代码里注释已经很清楚了,确实也没用到异步页面。不过有一个要注意的地方就是Session的读写锁,以前没关注这个,必须用EnableSessionState="ReadOnly"把读锁之间、分开,否则会造成请求阻塞,用两个页面是为了把登陆时的写锁和获取信息时的读锁分开,在这个问题上花了不少功夫。Session读写锁请参考:http://www.cnblogs.com/OpenCoder/archive/2010/01/10/1643659.html
微软有个signalR的东西专门做消息推送、及时消息这块的,有兴趣的同学可以看看,已经第二版了。
下一个博客会写某驾校约车插件,用chrome插件开发。拜拜
时间: 2024-09-27 20:00:43