• 发货源资源网

    [质量:5|效率:5|态度:5 ]

  • 当前位置:吉林福彩网 > 源码集市 > 聊天计数 >
    收藏商品 分享到:
    举报
    纯JS+MVC打造Web实时聊天室源码
    • 售  价:
    • 免费
    • 语  言:
    • C#
    • 数 据 库:
    • 品  牌:
    • WebForm
    • 最后更新:
    • 2012-12-01 09:12:51
    • 大  小:
    • 486.14KB MB
    • 演示网站:
    • 安装服务:
    • 免技术支持

      自动发货商品,随时可以购买,零等待。

      购买本商品,交易成功后可获赠积分。

      担保交易,有问题不解决24小时内可申请退款,安全保证。

    商品详情 交易评价 交易规则

    发货源资源网

    一、Web聊天室应用  

        要实现一个聊天系统,有很多方法可以用flash,html5里的WebSocket但是这两种办法因为要么要装插件,要么浏览器不支持,所以目前用的比较多的还是用纯js通过长轮询来实现。就我所知目前WebQQ,还有新浪微薄右下角的聊天系统都是采用这一方法来实现。

       相比普通扫描式的轮询,这种实现最主要的优点就是无用的请求会特别少我这里是2。5分钟一次,也就是说没有任何消息时每2。5分钟请求一次,腾讯好像是1分钟一次,这个看自己需求自己订吧,时间长点服务器压力小点,但稳定性差点,长期运行后自己去调节找一个好的平衡点吧。

    轮询

    二、具体实现

    • 前端用Jquery ajax来实现
       1         $(function () {
       2             window.polling = {
       3                 ///长连接地址
       4                 connectionUrl: "/channel/polling",
       5                 ///发送方式 
       6                 method: "POST",
       7                 ///事件载体
       8                 event_host: $("body"),
       9                 ///连接失败时重连接时间
      10                 period: 1000 * 20,
      11                 ///连接超时时间
      12                 timeOut: 180 * 1000,
      13                 v: 0,
      14                 ///连接ID
      15                 id: "",
      16                 error_num: 0,
      17                 Reconnect: function () {
      18                     polling.v++;
      19                     $。ajax({
      20                         url: polling.connectionUrl,
      21                         type: polling.method,
      22                         data: { id: polling.id, v: polling.v },
      23                         dataType: "json",
      24                         timeout: polling。timeOut,
      25                         success: function (json) {
      26                             polling.id = json.id;
      27                             ///版本号相同才回发服务器
      28                             if (json.v == polling.v)
      29                                 polling.Reconnect();
      30                             ///无消息返回时不处理
      31                             if (json.result == "-1")
      32                                 return;
      33                             $.each(json.datas, function (i, ajaxData) {
      34                                 ajaxData.data.type = ajaxData.t;
      35                                 polling.event_host.triggerHandler("sys_msg", [ajaxData.data]);
      36                             });
      37                         }, ///出错时重连
      38                         error: function () {
      39                             if (polling.error_num < 5) {
      40                                 setTimeout(polling.Reconnect, 1000 * 2);
      41                                 polling.error_num++;
      42                                 return;
      43                             }
      44                             ///20秒后重新连接
      45                             setTimeout(polling.Reconnect, polling.period);
      46                         }, ///释放资源
      47                         complete: function (XHR, TS) { XHR = null }
      48                     });
      49                 }
      50             }
      51             polling。Reconnect();
      52             /*-----------------------------------------------------------------------------*/
      53             ///新消息事件订阅
      54             $("body").bind("sys_msg", function (event, json) {
      55                 if (json.type != "1")
      56                     return;
      57                 $("#new_msg").append($("<p>" + json.content + "</p>"));
      58             });
      59             /*-----------------------------------------------------------------------------*/
      60             ///发送消息事件绑定
      61             $("#sendMsg").click(function () {
      62                 var self = $(this);
      63                 $.post("/home/addnewmsg", $("#msg").serialize(), null, "json")
      64             });
      65         });

    注意:因为网络经常会出现这样那样的问题所以保持连接时,如果连接时间超过自己设定的时间未响应,就应该要主动终结此次请求,而且每次请求都带上一个序号以保证消息序列,对于序号不对的请求应该予以丢弃.这里后面事件采用的是一种事件订阅的方式,方便每个不同页面订阅自己的事件而做出不同的处理方式

     

     

      根据消息类型不同,各自己处理自己想要消息

     

    • 后端用MVC来当服务器

    控制器

     1 [SessionState(SessionStateBehavior.ReadOnly)]
    2     public class ChannelController : AsyncController
    3     {
    4
    5         [HttpPost,AsyncTimeout(1000*60*4)]
    6         public void PollingAsync(int? id,int v)
    7         {
    8             AsyncManager.OutstandingOperations.Increment();
    9             AsyncManager.Parameters["Version"] = v;
    10             PollingMannger.AddConnection(id, AsyncManager);
    11         }
    12
    13
    14         public ActionResult PollingCompleted()
    15         {
    16             try
    17             {
    18                 (AsyncManager.Parameters["time"] as Timer).Dispose();
    19                 AsyncManager.Parameters["Finish"] = 1;
    20                 var v = AsyncManager.Parameters["Version"];
    21                 var id = AsyncManager.Parameters["id"];
    22                 if (!AsyncManager.Parameters.ContainsKey("Datas"))
    23                     return Json(new { result = "-1", v, id });
    24                 var datas = AsyncManager.Parameters["Datas"] as List<PollingMannger.ClientData>;
    25                 return Json(new { result = "-200", v, id, datas });
    26             }
    27             catch (Exception e)
    28             {
    29                 return Json(new { result = "-500" });
    30             }
    31         }
    32     }

     

     注意:1.首先我们应该让Controller继承自AsyncController这样才可以实现异步,提高服务器的吞吐量.如果是webform那就自己实现一下 IHttpAsyncHandler这个接口.

            2.这里让我头疼的问题就是因为这个长连接一直没响应,所以导致其他所有请求阻塞着,最后找来找去发现原来是Session的原因所以要在Controller上加上一个标记(怎么不能加在Action上呢,很郁闷!),加了这个后你不能对Session有写操作,不然会有异常的,请求阻塞的原因是Session上有个锁造成的.

     

      连接管理辅助类

      1 /// <summary>
      2     /// 连接数据管理类
      3     /// </summary>
      4     public class PollingMannger
      5     {
      6 
      7         [Serializable]
      8         public class ClientData
      9         {
     10             #region 消息类型
     11 
     12 
     13             /// <summary>
     14             /// 新消息
     15             /// </summary>
     16             public const int MsgNewInformation = 1;
     17 
     18 
     19             #endregion
     20 
     21 
     22 
     23             /// <summary>
     24             /// 消息类型
     25             /// 传送的数据
     26             /// </summary>
     27             /// <param name="type"></param>
     28             /// <param name="data"></param>
     29             public ClientData(int type, object data)
     30             {
     31                 this.t = type;
     32                 this.data = data;
     33             }
     34 
     35             /// <summary>
     36             /// 消息类型
     37             /// t=>Type
     38             /// </summary>
     39             public int t
     40             {
     41                 get;
     42                 private set;
     43             }
     44 
     45 
     46 
     47             /// <summary>
     48             /// 传送数据
     49             /// data=>Data
     50             /// </summary>
     51             public object data
     52             {
     53                 get;
     54                 private set;
     55             }
     56 
     57 
     58         }
     59 
     60 
     61         /// <summary>
     62         /// 发送信息委托
     63         /// </summary>
     64         /// <param name="to"></param>
     65         /// <param name="data"></param>
     66         public delegate void SendMessage(ClientData data);
     67 
     68         /// <summary>
     69         /// 连接管理定时器
     70         /// </summary>
     71         static Timer ManngerTime;
     72 
     73         public static SendMessage Send = new SendMessage(SendTo);
     74 
     75         /// <summary>
     76         /// 在线用户集合
     77         /// Dictionary 多线程出现高CPU问题
     78         /// 问题描述: http://blogs.msdn.com/b/tess/archive/2009/12/21/high-cpu-in-net-app-using-a-static-generic-dictionary.aspx
     79         /// </summary>
     80         //static Dictionary<int, PollingMannger> Online { get; set; }
     81         static Hashtable Online { get; set; }
     82         /// <summary>
     83         /// 连接自动超时时间
     84         /// </summary>
     85         static TimeSpan TimeOut = TimeSpan.FromSeconds(60 * 2.5);
     86 
     87         /// <summary>
     88         /// 最多连接数
     89         /// </summary>
     90         static int MaxConnection = 1000000;
     91 
     92         /// <summary>
     93         /// 连接ID随机数
     94         /// </summary>
     95         static Random radm = new Random(1);
     96 
     97         /// <summary>
     98         /// 连接对象
     99         /// </summary>
    100         /// <param name="connection"></param>
    101         static void RemoveConnection(PollingMannger connection)
    102         {
    103             if (connection == null)
    104                 return;
    105             Online。Remove(connection。Id);
    106             PollingMannger.SendTo(new ClientData(ClientData.MsgNewInformation, new { id = connection.Id }));
    107         }
    108 
    109         /// <summary>
    110         /// 将一个连接从集合中移除
    111         /// </summary>
    112         /// <param name="id">连接唯一标识ID</param>
    113         public static void RemoveConnection(int id, string userId)
    114         {
    115             try
    116             {
    117                 if (Online.ContainsKey(id))
    118                 {
    119                     var connection = Online[id] as PollingMannger;
    120                     RemoveConnection(connection);
    121                 }
    122             }
    123             catch (Exception e)
    124             {
    125                 ///多线程同时操作时有可能会不存在
    126             }
    127         }
    128 
    129         /// <summary>
    130         /// 添加或者激活一个新连接
    131         /// </summary>
    132         static public void AddConnection(int? id, AsyncManager asyncMannger)
    133         {
    134             if (id.HasValue && Online.ContainsKey(id.Value))
    135             {
    136                 (Online[id.Value] as PollingMannger).Active(asyncMannger);
    137                 return;
    138             }
    139             PollingMannger newConnection = new PollingMannger(asyncMannger);
    140             ///通知别人我上线了
    141             PollingMannger.SendTo(new ClientData(ClientData.MsgNewInformation, new { id = newConnection.Id, content = newConnection.Id + "上线了!" }));
    142         }
    143 
    144         /// <summary>
    145         /// 异步发送消息
    146         /// End
    147         /// </summary>
    148         /// <param name="asyncResult"></param>
    149         public static void EndSend(IAsyncResult asyncResult)
    150         {
    151             try
    152             {
    153                 Send。EndInvoke(asyncResult);
    154             }
    155             catch (Exception e)
    156             {
    157 
    158             }
    159         }
    160 
    161 
    162         /// <summary>
    163         /// 给所有人发送信息
    164         /// </summary>
    165         /// <param name="data">接收的数据</param>
    166         static void SendTo(ClientData data)
    167         {
    168             PollingMannger[] tempOnlines = new PollingMannger[Online.Values.Count + 10];
    169             Online.Values.CopyTo(tempOnlines, 0);
    170             var len = tempOnlines.Length;
    171             for (int i = 0; i < len; i++)
    172             {
    173                 try
    174                 {
    175                     PollingMannger polling = tempOnlines[i];
    176                     if (polling != null)
    177                         polling。AddStack(data);
    178                 }
    179                 catch (Exception e)
    180                 {
    181                     break;
    182                 }
    183             }
    184         }
    185 
    186         /// <summary>
    187         /// 异步发送消息
    188         /// Begin
    189         /// </summary>
    190         /// <param name="to"></param>
    191         /// <param name="data"></param>
    192         /// <param name="callBack"></param>
    193         /// <param name="object"></param>
    194         /// <returns></returns>
    195         public static IAsyncResult BeginSend(ClientData data, AsyncCallback callBack, object @object)
    196         {
    197             try
    198             {
    199                 return Send。BeginInvoke(data, callBack, @object);
    200             }
    201             catch (Exception e)
    202             {
    203                 return null;
    204             }
    205         }
    206 
    207         /// <summary>
    208         ///分配一个连接ID
    209         /// </summary>
    210         /// <returns></returns>
    211         static int GetNewId()
    212         {
    213             var tempId = radm。Next(MaxConnection);
    214             while (Online。ContainsKey(tempId))
    215                 tempId = radm.Next(MaxConnection);
    216             return tempId;
    217         }
    218 
    219         /// <summary>
    220         /// 用户是否在线
    221         /// </summary>
    222         /// <param name="uid">要判断的用户</param>
    223         /// <returns></returns>
    224         public static bool IsOline(string uid)
    225         {
    226             PollingMannger[] tempOnlines = new PollingMannger[Online.Values.Count + 10];
    227             Online.Values.CopyTo(tempOnlines, 0);
    228             for (int i = 0; i < tempOnlines.Length; i++)
    229             {
    230                 try
    231                 {
    232                     var tempOnline = tempOnlines[i];
    233                     if (tempOnline != null)
    234                         return true;
    235                 }
    236                 catch (Exception e)
    237                 {
    238                     break;
    239                 }
    240             }
    241             return false;
    242         }
    243 
    244         /// <summary>
    245         /// 静态变量初始化
    246         /// </summary>
    247         static PollingMannger()
    248         {
    249             //Online = new Dictionary<int, PollingMannger>();
    250             Online = new Hashtable();
    251             ///连接最大过期时间(也就是超过这个时间就会被清除)
    252             TimeSpan maxTimeOut = TimeSpan.FromMinutes(5);
    253             ///每隔5分钟进行一次连接清理
    254             ManngerTime = new Timer(o =>
    255             {
    256                 PollingMannger[] pollings = new PollingMannger[Online.Values.Count + 10];
    257                 Online.Values.CopyTo(pollings, 0);
    258                 int len = pollings.Length;
    259                 DateTime currentTime = DateTime。Now;
    260                 for (int i = 0; i < len; i++)
    261                 {
    262                     try
    263                     {
    264                         var tempPolling = pollings[i];
    265                         if (tempPolling == null)
    266                             continue;
    267                         ///移除长时没有用的连接
    268                         if ((currentTime - tempPolling.LastActiveTime).TotalMinutes > maxTimeOut.TotalMinutes)
    269                         {
    270                             RemoveConnection(tempPolling);
    271                             ///如果这个连接还没响应就先响应掉
    272                             if (!tempPolling.AsyncMannger.Parameters.ContainsKey("Finish"))
    273                                 tempPolling.AsyncMannger.Finish();
    274                         }
    275 
    276                     }
    277                     catch (Exception e)
    278                     {
    279 
    280                     }
    281                 }
    282             }, null, maxTimeOut, TimeSpan.FromMinutes(10));
    283         }
    284 
    285         public PollingMannger(AsyncManager asyncManager)
    286         {
    287             this.TaskQueue = new Queue<ClientData>();
    288             this.LastActiveTime = DateTime。Now;
    289             this.Id = GetNewId();
    290             this.AsyncMannger = asyncManager;
    291             asyncManager.Parameters["id"] = Id;
    292             ///将自己添加入连接集合
    293             Online.Add(Id, this);
    294         }
    295 
    296         /// <summary>
    297         /// 心跳激活
    298         /// </summary>
    299         /// <param name="asyncManager"></param>
    300         public void Active(AsyncManager asyncManager)
    301         {
    302             asyncManager.Parameters["id"] = this。Id;
    303             this.LastActiveTime = DateTime。Now;
    304             this.AsyncMannger = asyncManager;
    305             DequeueTask();
    306         }
    307 
    308         /// <summary>
    309         /// 任务队列
    310         /// </summary>
    311         Queue<ClientData> TaskQueue { get; set; }
    312 
    313         /// <summary>
    314         /// 最后激活时间
    315         /// </summary>
    316         public DateTime LastActiveTime { get; set; }
    317 
    318         /// <summary>
    319         /// 连接唯一编号 
    320         /// </summary>
    321         public int Id { get; set; }
    322 
    323 
    324         AsyncManager asyncMannger;
    325 
    326         /// <summary>
    327         /// 当前连接的上下文
    328         /// </summary>
    329         public AsyncManager AsyncMannger
    330         {
    331             get { return asyncMannger; }
    332             set
    333             {
    334                 var mySession = this;
    335                 asyncMannger = value;
    336                 var tempMannger = value;
    337                 Timer tempTime = null;
    338                 tempTime = new Timer(o =>
    339                 {
    340                     if (!tempMannger.Parameters.ContainsKey("Finish"))
    341                         tempMannger。Finish();
    342                 }, null, TimeOut, TimeSpan.FromSeconds(0));
    343                 tempMannger.Parameters["time"] = tempTime;
    344             }
    345         }
    346 
    347 
    348         /// <summary>
    349         /// 添加一要运送的数据
    350         /// 注意:要可序列化
    351         /// </summary>
    352         /// <param name="type">消息类型</param>
    353         /// <param name="data">要传送的数据</param>
    354         void AddStack(ClientData clientData)
    355         {
    356             this.TaskQueue.Enqueue(clientData);
    357             if (!this.asyncMannger.Parameters.ContainsKey("Finish"))
    358                 DequeueTask();
    359         }
    360 
    361         /// <summary>
    362         ///完成队列中的任务
    363         /// </summary>
    364         void DequeueTask()
    365         {
    366             if (this.TaskQueue.Count > 0)
    367             {
    368                 List<ClientData> datas = new List<ClientData>();
    369                 while (this.TaskQueue.Count > 0)
    370                     datas.Add(this.TaskQueue.Dequeue());
    371                 this.asyncMannger.Parameters["Datas"] = datas;
    372                 this.asyncMannger.Finish();
    373             }
    374         }
    375 
    376     }

     

     

      注意吉林福彩网:这里用了一个队列来存储需要发送的消息,当每次请求回到服务器时先检查队列中有没有要运送的消息,如果有就将消息发给浏览器,没有就一直等待,直到超时时间到期时自动响应一个空消息给浏览器,浏览器再回发,形成一个循环.

     

    效果

     

     


    最后想跟大家探讨一下多线程的锁问题:

    这里面一个静态的连接管理对像 

    我一开始用Dictionary因为我没加锁,所以在多线程同时调Add和ContainsKey(id)时出现高CPU现像(CPU 100%),

    抓了个Dump后面找朋友用windbg帮忙分析一下,Dictionary的add里有个循环所以CPU 100%

    代码如下:

    描述(),后来换成Hashtable好点目前还没出现问题

    因为多线程这里多线程同时操作这个集合时容易出现问题,加锁的话又会降低效率,所想请各位高手指点一下,如何高效的操作这些集合,我这里没有加锁,复制一个副本出来遍历,只是将其中出现的异常将其屏蔽掉了。

    所以希望高手们指点指点,大家平常多线程操作集合时是怎么高效操作的.

    交易评价
      (0)
      <

      1/5

      >
    交易规则
    • 交易流程
    • 发货方式
    • 1、自动:在上方保障服务中标有自动发货的商品,拍下后,将会自动收到来自卖家的商品获取(下载)链接;

      2、手动:未标有自动发货的的商品,拍下后,卖家会收到邮件、短信提醒,也可通过QQ或订单中的电话联系对方。

    • 退款说明
    • 1、描述:吉林福彩网源码描述(含标题)与实际源码不一致的(例:描述PHP实际为ASP、描述的功能实际缺少、版本不符等);

      2、演示:有演示站时,与实际源码小于95%一致的(但描述中有"不保证完全一样、有变化的可能性"类似显著声明的除外);

      3、发货:手动发货源码,在卖家未发货前,已申请退款的;

      4、服务:卖家不提供安装服务或需额外收费的(但描述中有显著声明的除外);

      5、其他:如质量方面的硬性常规问题等。

      注:经核实符合上述任一,均支持退款,但卖家予以积极解决问题则除外。交易中的商品,卖家无法对描述进行修改!

    • 注意事项
    • 1、在未拍下前,双方在QQ上所商定的内容,亦可成为纠纷评判依据(商定与描述冲突时,商定为准);

      2、在商品同时有网站演示与图片演示,且站演与图演不一致时,默认按图演作为纠纷评判依据(特别声明或有商定除外);

      吉林福彩网3、在没有"无任何正当退款依据"的前提下,写有"一旦售出,概不支持退款"等类似的声明,视为无效声明;

      4、虽然交易产生纠纷的几率很小,但请尽量保留如聊天记录这样的重要信息,以防产生纠纷时便于16Aspx源码介入快速处理。

    • 16Aspx源码声明
    • 1、16Aspx源码作为第三方中介平台,依据交易合同(商品描述、交易前商定的内容)来保障交易的安全及买卖双方的权益;

      2、非平台线上交易的项目,出现任何后果均与16Aspx源码无关;无论卖家以何理由要求线下交易的,请联系管理举报。

  • 宝贝数量:7598
  • 创店时间:2017/5/26 16:11:00
  • 联系客服

    330199865

    店内搜索
  • 商品:
  • 价格: -
  • 本店销量榜

    1微信公众平台Bee。WeiXin开发源码

    2BS拖拽工作流设计及研发源码

    3通用权限管理系统(含文档、数据库)源码

    4Easyui之权限系统源码

    5ASP.NETMVC+EF框架+EasyUI实现权限管理源码

    6通用OA系统增强源码

    7Entity Framework4.1+MVC3+Jquery EasyUI的DEMO源码

    8基于FineUI的通用权限管理框架源码

    9WPF仿迅雷7界面UI效果

    10WEB在线流程图设计器GOOFLOW源码

    广而告之
    浙江福彩网 玖玖棋牌游戏 吉林福彩网 江西快3 北京体彩网 浙江福彩 江西快3走势图 玖玖棋牌app 浙江福彩 北京福彩网