1、Html5WebSocket介绍html
WebSocket protocol 是HTML5一种新的协议(protocol)。它是实现了浏览器与服务器全双工通讯(full-duplex)。json
如今,不少网站为了实现即时通信(real-time),所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(time interval)(如每1秒),由浏览器对服务器发出HTTP request,而后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request d的模式带来很明显的缺点 – 浏览器须要不断的向服务器发出请求(request),然而HTTP request 的header是很是长的,里面包含的数据可能只是一个很小的值,这样会占用不少的带宽。浏览器
而最比较新的技术去作轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通讯,但依然须要发出请求(reuqest)。服务器
在 WebSocket API,浏览器和服务器只须要要作一个握手的动做(其实是tcp),而后,浏览器和服务器之间就造成了一条快速通道(这里走的是新的协议)。二者之间就直接能够数据互相传送。网络
2、IM系统的几种通讯方式app
1.点对点通讯(对等通讯方式):客户端A想要与客户端B进行通讯,首页会与IM服务器进行一次握手,而后从IM服务器拿到客户端B的地址。而后直接向客户端B发送消息,而后客户端B获取到A客户端的地址,也直接向客户端A回复消息,这样就不经过IM服务器来中转,这样双方的即时文字消息就不经过 IM服务器中转,而是经过网络进行点对点的直接通信,这称为对等通信方式(Peer To Peer) 。PS:这种方式须要作内网穿透或代理,否则没法获取到对方的地址等信息。socket
2.代理通讯:当客户端A与客户端B之间存在防火墙,网速很慢等缘由,IM服务器能够提供消息中专的服务,客户端A先把消息发送到IM服务器,而后再经过IM服务器把消息转发给客户端B,这样无需获得客户端的地址信息就能实现消息送达,这种方式叫作代理通讯。async
3.离线代理通讯:当客户端A想要与客户端B通讯的时候,发现客户端B不在线,这样IM服务器会把消息存起来,等到下一次客户端B上线的时候,由客户端B主动获取到离线消息(这样作好像能够下降服务器的压力)。tcp
3、利用Html5的WebSocket实现简单的聊天室ide
1.服务端代码以下,注释那些都挺全的,就不一一多说:
1 private async Task WebSocketContext(AspNetWebSocketContext context) 2 { 3 try 4 { 5 WebSocket socket = context.WebSocket; 6 7 //获取链接信息 8 string user_name = TDCMS.Common.TD_Request.GetQueryStringValue("user_name", ""); 9 10 //第一次open时,添加到链接池中 11 if (_userPool.Find(c => c.User_name== user_name) == null) 12 { 13 _userPool.Add(new UserPool() { User_name = user_name , Socket = socket }); 14 } 15 else 16 { 17 UserPool p = _userPool.Find(c => c.User_name == user_name); 18 if (socket != p.Socket)//当前对象不一致,更新 19 { 20 p.Socket = socket; 21 } 22 } 23 24 UserPool sourcePool= _userPool.Find(c => c.User_name == user_name);//获取到发送者链接池 25 26 #region 对全部链接池中广播 我上线了 27 foreach (var item in _userPool) 28 { 29 MessageModel model = new MessageModel() 30 { 31 Aim = item.User_name, 32 Contents = user_name + "上线了", 33 Source = sourcePool.User_name, 34 Status = 1 35 }; 36 await item.Socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonHelper.ObjectToJson(model))), WebSocketMessageType.Text, true, CancellationToken.None); 37 } 38 #endregion 39 40 bool isNext = true; 41 while (isNext) 42 { 43 if (socket.State == WebSocketState.Open) 44 { 45 ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]); 46 WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None); 47 48 #region 关闭Socket处理,删除链接池 49 if (socket.State != WebSocketState.Open)//链接关闭 50 { 51 if (_userPool.Find(c => c.User_name == user_name) != null) 52 _userPool.Remove(_userPool.Find(c => c.User_name == user_name));//删除链接池 53 //广播当前在线的用户 我下线了 54 foreach (var item in _userPool) 55 { 56 MessageModel offline = new MessageModel() 57 { 58 Aim = item.User_name, 59 Contents = user_name + "下线了", 60 Source = sourcePool.User_name, 61 Status = 1 62 }; 63 await item.Socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonHelper.ObjectToJson(offline))), WebSocketMessageType.Text, true, CancellationToken.None); 64 } 65 break; 66 } 67 68 #endregion 69 70 #region 若是链接没有关闭,处理发送过来的消息 71 72 MessageModel model=new MessageModel(); 73 int messageCount = result.Count; 74 string messageStr= Encoding.UTF8.GetString(buffer.Array, 0, messageCount); 75 model = JsonHelper.JsonToObject<MessageModel>(messageStr);//这个是解析好的 消息 76 77 //发送消息到每一个客户端 78 foreach (var item in _userPool) 79 { 80 await item.Socket.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes(JsonHelper.ObjectToJson(model))), WebSocketMessageType.Text, true, CancellationToken.None); 81 } 82 83 #endregion 84 } 85 } 86 87 } 88 catch(Exception ex) 89 { 90 throw ex; 91 } 92 }
2.客户端JS代码以下:
1 <script> 2 var im;//WebSocket对象 3 function initIm() { 4 var user=$('#txtUserName').val(); 5 im = new MyIm(window.location.hostname, window.location.port, user); 6 $('.online').show(); 7 $('.offline').hide(); 8 im.Init(); 9 } 10 11 //建立一个对象 里面有3个方法,分别为Init:初始化Socket链接、Send:发送消息、Colse:关闭链接 12 var MyIm = function (path, prot, user_name) { 13 this.requestPath = 'ws://' + path + ':' + prot + '/tools/Handler.ashx'; 14 this.user_name = user_name; 15 this.param = '?user_name=' + this.user_name; 16 this.socekt; 17 18 } 19 MyIm.prototype = { 20 Init: function () { 21 this.socekt = new WebSocket(this.requestPath + this.param); 22 this.socekt.onopen = function () { 23 addSysMessage('链接成功','') 24 };//链接成功 25 this.socekt.onmessage = function (result) { 26 //这里返回的消息为json格式,里面的data为服务器返回的内容 27 var json = eval('(' + result.data + ')'); 28 if (Number(json.Status) == 1) { 29 addSysMessage(json.Contents,json.Time) 30 } else { 31 addMessage(json); 32 } 33 };//接收到消息的时候 34 this.socekt.onclose = function (result) { 35 addSysMessage('个人链接关闭了','') 36 }//链接关闭的时候 37 this.socekt.onerror = function (result) { 38 addSysMessage('网络发生了错误', '');//当这一步被执行时,close会被自动执行,因此无需主动去执行关闭方法 39 }//当链接发生错误的时候 40 }, 41 Send: function (msg) { 42 //这里能够直接发送消息给服务器,可是为了让服务器好区分个人消息是属于通知仍是普通消息仍是其余,因此作成了json 43 //后台获取到json,解析后针对不一样的消息类型进行处理 44 var json = '{"Status":0,"Contents":"'+msg+'","Source":"'+this.user_name+'","Aim":""}'; 45 this.socekt.send(json); 46 }, 47 Close: function () { 48 if (this.socekt != null) { 49 this.socekt.close(); 50 return; 51 } 52 } 53 } 54 //把通知消息载入到通知列表 55 function addSysMessage(msg, time) { 56 if (time.length <= 0) { 57 time = new Date(); 58 } 59 $('.messageBox').append('<li><p class="time">' + time + '</p><p class=\"message\">' + msg + '</p></li>'); 60 } 61 //把聊天消息载入到聊天框 62 function addMessage(json) { 63 $('.mainBox').append('<li><p class="time">' + json.Time + '</p><p class=\"message\"><span>'+json.Source+'说:</span>' + json.Contents + '</p></li>'); 64 } 65 //发送消息 66 function sendMsg() { 67 var contents = $('#txtContents').val(); 68 im.Send(contents); 69 } 70 //关闭链接 71 function offLine() { 72 im.Close(); 73 74 $('.online').hide(); 75 $('.offline').show(); 76 } 77 </script>
3.客户端HTML:
<div class="mainIm"> <div> <ul class="mainBox"> </ul> <ul class="messageBox"> </ul> </div> <div class="online" style="display:none;"> <input type="text" id="txtContents" placeholder="输入要发送的内容" /> <input type="button" value="发送" onclick="sendMsg()" /><input type="button" value="断开链接" onclick="offLine()" /> </div> <div class="offline"> <input type="text" id="txtUserName" placeholder="请输入一个用户名" /> <input type="button" value="链接" onclick="initIm()" /> </div> </div>
4.最后的效果以下:
3、总结
目前IE并不支持WebSocket,就目前来讲,这种方式并不适用于大范围使用。
这里只是实现了简单的聊天室,若是想要一对一,只需找到用户的链接池,向该链接池发送消息便可,若是用户不存在,能够建立一个全局变量离线消息池来储存离线消息。
若有大神发现写的不会的地方,请多多指教!!!