好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

C#制作简单的多人在线即时交流聊天室

实现网页版的在线聊天室的方法有很多,在没有来到html5之前,常见的有:定时轮询、长连接+长轮询、基于第三方插件(如flash的socket),而如果是html5,则比较简单,可以直接使用websocket,当然html5目前在pc端并没有被所有浏览器支持,所以我的这个聊天室仍是基于长连接+长轮询+原生的js及ajax实现的多人在线即时交流聊天室,这个聊天室其实是我上周周末完成的,功能简单,可能有些不足,但可以满足在线即时聊天需求,分享也是给大家提供一个思路,大家可以基于此来实现更好的在线即时聊天工具。

聊天室功能简介:

1。支持多人进入同一个聊天室聊天;

2。进入即离线均会自动生成通知信息显示在聊天室中,这样聊天的人们就知道谁进来了谁离开了;

3。实时显示在线人员表列;

4。无需数据库支持,全部存在内存中,当然有条件的可以采用分布式缓存或加一个数据库来存,这里演示就是用内存来存了。

下面就开始分享我的代码,由于采用原生的js及ajax,所以简单易懂,代码分别web前端及服务端(有点废话了)

web前端源代码如下:(chatpage.html)

?

<!doctype html>

<html xmlns= "http://www.w3.org/1999/xhtml" >

<head>

   <meta http-equiv= "content-type" content= "text/html; charset=utf-8" />

   <title></title>

   <style type= "text/css" >

     html, body {

       margin: 0px;

       padding: 0px;

       width: 100%;

       height: 100%;

       background-color: #f8f7f7;

       font-family: arial,sans-serif;

     }

 

     #layouttable {

       margin:0px;

       padding:0px;

       width:100%;

       height:100%;

       border:2px solid green;

       border-collapse:collapse;

       min-width:800px;

     }

 

       #layouttable td {

         border: 1px solid green;

       }

 

     .h100p {

       height:100%;

     }

 

     .midtr{height:auto;}

       .midtr tr td {

         height: 100%;

       }

 

     #chatmsgbox, #chatonlinebox {

       background-color:white;

       overflow-x: hidden;

       overflow-y: auto;

       overflow-wrap: break -word;

       height: 100%;

     }

 

     #chatonlinebox {

       background-color: #f5d0a8;

     }

 

     .rc, .sd {

       overflow:hidden;

     }

 

      .rc p {

       float: left;

       color: green;

     }

       .sd p {

         float: right;

         color: orange;

       }

   </style>

 

</head>

<body>

   <table id= "layouttable" >

     <colgroup>

       <col style= "width:auto" />

       <col style= "width: 200px;" />

     </colgroup>

     <tr style= "height:30px; background-color:lightblue;color:yellow;" >

       <td>

         欢迎进入梦在旅途的网页即时在线大众聊天室 - www.zuowenjun.cn:

       </td>

       <td>

         当前在线人员

       </td>

     </tr>

     <tr style= "height:auto;" id= "midtr" >

       <td>

         <div id= "chatmsgbox" >

         </div>

       </td>

       <td>

         <div id= "chatonlinebox" >

           <ul id= "chatnames" ></ul>

         </div>

       </td>

     </tr>

     <tr style= "height:50px;" >

       <td colspan= "2" >

         <label for = "name" >聊天妮称:</label>

         <input type= "text" id= "name" style= "width:80px;" />

         <input type= "button" id= "btnsavename" value= "确认进入" />

         <label for = "msg" >输入内容:</label>

         <input type= "text" id= "msg" style= "width:400px;" />

         <input type= "button" id= "btnsend" value= "发送消息" disabled= "disabled" />

       </td>

     </tr>

   </table>

   <script type= "text/javascript" >

     var chatname = null ;

     var ochatmsgbox, omsg, ochatnames;

     var ajaxforsend, ajaxforrecv;

 

     //页面加载初始化

     window.onload = function () {

       document.getelementbyid( "btnsavename" ).onclick = function () {

         this .disabled = true ;

         var oname = document.getelementbyid( "name" );

         oname.readonly = true ;

         document.getelementbyid( "btnsend" ).disabled = false ;

         //receivemsg();

         setchatstatus(oname.value, "on" );

       }

 

       document.getelementbyid( "btnsend" ).onclick = function () {

         sendmsg(omsg.value);

       };

 

       //init

       ochatmsgbox = document.getelementbyid( "chatmsgbox" );

       omsg = document.getelementbyid( "msg" );

       ochatnames = document.getelementbyid( "chatnames" );

       ajaxforsend = getajaxobject();

       ajaxforrecv = getajaxobject();

     }

 

     //离开时提醒

     window.onbeforeunload = function () {

       event.returnvalue = "您确定要退出聊天室吗?" ;

     }

 

     //关闭时离线

     window.onunload = function () {

       setchatstatus(chatname, "off" );

     }

 

     //设置聊天状态:在线 or 离线

     function setchatstatus(name, status) {

       callajax(getajaxobject(), "action=" + status + "&name=" + name, function (rs) {

         if (!rs.success) {

           alert(rs.info);

           return ;

         }

         if (status == "on" ) {

           chatname = document.getelementbyid( "name" ).value;

           settimeout( "receivemsg()" ,500);

         }

         loadonlinechatnames();

       });

     }

 

     //加载在线人员名称列表

     function loadonlinechatnames(){

       callajax(getajaxobject(), "action=onlines" , function (rs) {

         var lis = "" ;

         for ( var i=0;i<rs.length;i++)

         {

           lis += "<li>" + rs[i] + "</li>" ;

         }

         ochatnames.innerhtml = lis;

       });

     }

 

     //接收消息列表

     function receivemsg() {

       callajax(ajaxforrecv, "action=receive&name=" + chatname, function (rs) {

         if (rs.success) {

           showchatmsgs(rs.msgs, "rc" );

         }

         settimeout( "receivemsg()" , 500);

       });

     }

     //发送消息

     function sendmsg(msg) {

       callajax(ajaxforsend, "action=send&name=" + chatname + "&msg=" + escape(msg), function (rs) {

         if (rs.success) {

           showchatmsgs(rs.msgs, "sd" );

           omsg.value = null ;

           //alert("发送成功!");

         }

       });

     }

 

     //显示消息

     function showchatmsgs(msgs, cssclass) {

       var loadonline = false ;

       for ( var i = 0; i < msgs.length; i++) {

         var msg = msgs[i];

         ochatmsgbox.innerhtml += "<div class='" + cssclass + "'><p>[" + msg.name + "] - " + msg.sendtime + " 说:<br/>" + msg.content + "</p></div>" ;

         if (msg.type == "on" || msg.type == "off" )

         {

           loadonline = true ;

         }

       }

       if (loadonline)

       {

         loadonlinechatnames();

       }

     }

 

     //调用ajax

     function callajax(ajax, param, callback) {

 

       ajax.open( "post" , "chathandler.ashx" , true );

       ajax.setrequestheader( "content-type" , "application/x-www-form-urlencoded" );

       ajax.onreadystatechange = function () {

         if (ajax.readystate == 4 && ajax.status == 200) {

           var json = eval( "(" + ajax.responsetext + ")" );

           callback(json);

         }

       };

       ajax.send(param);

     }

 

     //获取ajax对象(xmlhttprequest)

     function getajaxobject() {

       var xmlhttp;

       if (window.xmlhttprequest) { // code for ie7+, firefox, chrome, opera, safari

         xmlhttp = new xmlhttprequest();

       }

       else { // code for ie6, ie5

         xmlhttp = new activexobject( "microsoft.xmlhttp" );

       }

       return xmlhttp;

     }

 

   </script>

</body>

</html>

代码很简单,并都有注释,在此就不作说明了,如果有疑问欢迎在下方评论。

服务端(chathandler.ashx) 

?

<%@ webhandler language= "c#" class = "chathandler" %>

 

using system;

using system.web;

using system.collections;

using system.collections.generic;

using system.linq;

using system.web.script.serialization;

using system.threading;

using system.collections.concurrent;

 

public class chathandler : ihttphandler

{

 

   private class msg

   {

     public string name { get ; set ; }

     public string sendtime { get ; set ; }

     public string content { get ; set ; }

     public string readednams { get ; set ; }

     public int readedcount { get ; set ; }

     public string type { get ; set ; }

   }

 

   private static list<msg> msgs = new list<msg>();

   private static readerwriterlockslim rwlock = new readerwriterlockslim();

   private static object syncobject = new object (),syncobject1 = new object ();

   private static list< string > onlinenames = new list< string >();

 

   public void processrequest(httpcontext context)

   {

     string chatname = context.request.form[ "name" ];

     string msg = context.request.form[ "msg" ];

     string actionname = context.request.form[ "action" ];

     javascriptserializer jsserializer = new javascriptserializer();

 

     object responseobject = null ;

 

     switch (actionname)

     {

       case "receive" :

         {

           responseobject = getnewmessages(chatname);

           break ;

         }

       case "send" :

         {

           responseobject = sendmessage(chatname, msg, "normal" );

           break ;

         }

       case "on" :

       case "off" :

         {

           responseobject = setchatstatus(chatname, actionname);

           break ;

         }

       case "onlines" :

         {

           responseobject = onlinenames;

           break ;

         }

     }

 

     context.response.contenttype = "text/json" ;

     context.response.write(jsserializer.serialize(responseobject));

 

   }

 

   private object setchatstatus( string chatname, string status)

   {

     if (status == "on" )

     {

       if (onlinenames.exists(s => s == chatname))

       {

         return new { success = false , info = "该聊天妮称已经存在,请更换一个名称吧!" };

       }

       lock (syncobject1)

       {

         onlinenames.add(chatname);

       }

       sendmessage(chatname, "大家好,我进入聊天室了!" , status);

       return new { success = true , info = string .empty };

     }

     else

     {

       lock (syncobject1)

       {

         onlinenames.remove(chatname);

       }

       sendmessage(chatname, "再见,我离开聊天室了!" , status);

       return new { success = true , info = string .empty };

     }

   }

 

   /// <summary>

   /// 获取未读的新消息

   /// </summary>

   /// <param name="chatname"></param>

   /// <returns></returns>

   private object getnewmessages( string chatname)

   {

     //第一种:循环处理

     while ( true )

     {

 

       var newmsgs = msgs.where(m => m.name != chatname && !(m.readednams ?? "" ).contains(chatname)).orderby(m => m.sendtime).tolist();

       if (newmsgs != null && newmsgs.count() > 0)

       {

         lock (syncobject)

         {

           newmsgs. foreach ((m) =>

           {

             m.readednams += chatname + "," ;

             m.readedcount++;

           });

           int chatnamecount = onlinenames.count();

           msgs.removeall(m => m.readedcount >= chatnamecount);

         }

 

         return new { success = true , msgs = newmsgs };

       }

 

       thread.sleep(1000);

     }

 

 

     //第二种方法,采用自旋锁

     //list<msg> newmsgs = null;

     //spinwait.spinuntil(() =>

     //{

     //  newmsgs = msgs.where(m => m.name != chatname && !(m.readednams ?? "").contains(chatname)).orderby(m => m.sendtime).tolist();

     //  return newmsgs.count() > 0;

     //}, -1);

 

     //rwlock.enterwritelock();

     //newmsgs.foreach(m =>

     //{

     //  m.readednams += chatname + ",";

     //  m.readedcount++;

     //});

     //rwlock.exitwritelock();

     //return new { success = true, msgs = newmsgs };

   }

 

   /// <summary>

   ///

   /// </summary>

   /// <param name="chatname"></param>

   /// <param name="msg"></param>

   /// <returns></returns>

   private object sendmessage( string chatname, string msg, string type)

   {

     var newmsg = new msg() { name = chatname, sendtime = datetime.now.tostring( "yyyy/mm/dd hh:mm" ), content =httpcontext.current.server.htmlencode(msg), readednams = null , type = type };

     //rwlock.enterwritelock();

     lock (syncobject)

     {

       msgs.add(newmsg);

     }

     //rwlock.exitwritelock();

     return new { success = true , msgs = new [] { newmsg } };

   }

 

 

 

   public bool isreusable

   {

     get

     {

       return false ;

     }

   }

 

}

代码也相对简单,实现原理主要是:

1。聊天消息:循环获取未读的消息,在取出读的消息同时,将其标识为已读,全部已读的消息则删除;--我这里采用了两种方法,第二种方法被注释掉了,大家可以取消注释试试,也是不错的,比第一种更直观,建议使用;

2。发送消息:实例化一个消息实例并加入到聊天消息集合中;

3。状态切换:上线则加入到在线人员集合中,并生成一条上线消息放入到聊天消息集合中,离线则从在线人员集合中移除该人员信息,并生成一条离线消息放入聊天消息集合中;

注意事项,由于采用了全局静态集合,所以线程同步比较重要。

最终的实现效果展示如下:

 张三:

李四:

小美:

如果觉得不错的话,给个推荐吧,你的支持是推动我不断前进的动力及写作的源泉,我一直坚持:知识在于分享,分享的同时自己也在成长,希望与大家共同成长,谢谢!

dy("nrwz");

查看更多关于C#制作简单的多人在线即时交流聊天室的详细内容...

  阅读:97次