谁说长连接、长轮询必须用异步!

看了好多帖子一说长连接、长轮询、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插件开发。拜拜

 

你可能感兴趣的:(长连接)