首页 > 代码库 > 谁说长连接、长轮询必须用异步!
谁说长连接、长轮询必须用异步!
看了好多帖子一说长连接、长轮询、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插件开发。拜拜
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。