使用Html5下WebSocket搭建简易聊天室

一、Html5WebSocket介绍

WebSocket protocol 是HTML5一种新的协议(protocol)。它是实现了浏览器与服务器全双工通信(full-duplex)。

现在,很多网站为了实现即时通讯(real-time),所用的技术都是轮询(polling)。轮询是在特定的的时间间隔(time interval)(如每1秒),由浏览器对服务器发出HTTP request,然后由服务器返回最新的数据给客服端的浏览器。这种传统的HTTP request d的模式带来很明显的缺点 – 浏览器需要不断的向服务器发出请求(request),然而HTTP request 的header是非常长的,里面包含的数据可能只是一个很小的值,这样会占用很多的带宽。

而最比较新的技术去做轮询的效果是Comet – 用了AJAX。但这种技术虽然可达到全双工通信,但依然需要发出请求(reuqest)。

在 WebSocket API,浏览器和服务器只需要要做一个握手的动作(实际上是tcp),然后,浏览器和服务器之间就形成了一条快速通道(这里走的是新的协议)。两者之间就直接可以数据互相传送。

二、IM系统的几种通信方式

1.点对点通信(对等通信方式):客户端A想要与客户端B进行通信,首页会与IM服务器进行一次握手,然后从IM服务器拿到客户端B的地址。然后直接向客户端B发送消息,然后客户端B获取到A客户端的地址,也直接向客户端A回复消息,这样就不通过IM服务器来中转,这样双方的即时文字消息就不通过 IM服务器中转,而是通过网络进行点对点的直接通讯,这称为对等通讯方式(Peer To Peer) 。PS:这种方式需要做内网穿透或代理,不然无法获取到对方的地址等信息。

2.代理通信:当客户端A与客户端B之间存在防火墙,网速很慢等原因,IM服务器可以提供消息中专的服务,客户端A先把消息发送到IM服务器,然后再通过IM服务器把消息转发给客户端B,这样无需得到客户端的地址信息就能实现消息送达,这种方式叫做代理通信。

3.离线代理通信:当客户端A想要与客户端B通信的时候,发现客户端B不在线,这样IM服务器会把消息存起来,等到下一次客户端B上线的时候,由客户端B主动获取到离线消息(这样做好像可以降低服务器的压力)。

三、利用Html5的WebSocket实现简单的聊天室

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.最后的效果如下:

三、总结

目前IE并不支持WebSocket,就目前来说,这种方式并不适用于大范围使用。

这里只是实现了简单的聊天室,如果想要一对一,只需找到用户的连接池,向该连接池发送消息即可,如果用户不存在,可以创建一个全局变量离线消息池来储存离线消息。

如有大神发现写的不会的地方,请多多指教!!!

时间: 2024-10-02 19:00:04

使用Html5下WebSocket搭建简易聊天室的相关文章

php+websocket搭建简易聊天室实践

1.前言 公司游戏里面有个简单的聊天室,了解了之后才知道是node+websocket做的,想想php也来做个简单的聊天室.于是搜集各种资料看文档.找实例自己也写了个简单的聊天室. http连接分为短连接和长连接.短连接一般可以用ajax实现,长连接就是websocket.短连接实现起来比较简单,但是太过于消耗资源.websocket高效不过兼容存在点问题.websocket是html5的资源 如果想要详细了解websocket长连接的原理请看https://www.zhihu.com/ques

Html Websocket搭建右下角聊天室

最近闲来无事,为我的网站增加了聊天室功能,这里主要用到了websocket技术,这时html5的一种新技术 controller部分 package main.java.web.news; import java.io.IOException; import java.util.concurrent.CopyOnWriteArraySet; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; /** *

基于spring4 websocket的简易聊天室

一:创建maven webapp项目 编辑pom.xml文件 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0

websocket之简易聊天室

一,带昵称的群聊 #!/usr/bin/env python # -*- coding:utf8 -*- import json from flask import Flask, request, render_template from geventwebsocket.websocket import WebSocket from gevent.pywsgi import WSGIServer from geventwebsocket.handler import WebSocketHandl

docker搭建swoole简易聊天室

docker搭建swoole的简易聊天室 首先pull镜像 docker pull docker.io/kong36088/nginx-php7-swoole 创建容器 docker run --name {自己创建的名字} -p 9501:9501 -p 8089:80 -d -it kong36088/nginx-php7-swoole /bin/bash 进入容器 docker exec -it {容器名字或id} /bin/bash 进入容器之后进入nginx配置文件 cd /etc/n

Java和WebSocket开发网页聊天室

小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项目简介 WebSocket是HTML5一种新的协议,它实现了浏览器与服务器全双工通信,这里就将使用WebSocket来开发网页聊天室,前端框架会使用AmazeUI,后台使用Java,编辑器使用UMEditor. 二.涉及知识点 网页前端(HTML+CSS+JS)和Java 三.软件环境 Tomcat

socket.io入门,简易聊天室

介绍 通常我们web使用的是http协议,但是 HTTP 协议有一个缺陷:通信只能由客户端发起. 所以我们需要一个可以由服务端主动发出的协议,即WebSocket. WebSocket是HTML5新增的一种通信协议,其特点是服务端可以主动向客户端推送信息,客户端也可以主动向服务端发送信息,是真正的双向平等对话,属于服务器推送技术的一种. Socket.IO 是一个基于 Node.js 的实时应用程序框架,在即时通讯.通知与消息推送,实时分析等场景中有较为广泛的应用. socket.io 包含两个

nodejs入门——搭建一个聊天室应用

个人博客 http://mvc.coding.io/ 1入门教程推荐 node入门 很早之前看的就是这个,比较浅显易懂,看一遍就明白nodejs到底是怎么一回事儿了 2开源项目 昨天在coding上看到了一个nodejs聊天室,fork了一份 nodejs聊天室 3环境搭建 nodejs官网,下载最新版本(本人电脑win7 64位),安装过程下一步下一步就行,安装会自动配置环境变量, 建议安装目录自己选择一下,别默认安装在C:\Program Files\ 目录下(目录有空格 会出现一些问题)

使用WebSocket实现网页聊天室

知道WebSocket挺久了,但是一直没提起兴趣去了解它. 今天听@成熟的毛毛虫 说到slack.小小的试用了一下,发现slack的聊天功能做得相当强大,看了下网络请求,发现是基于WebSocket实现的.顿时提起兴趣,想了解下这强大的WebSocket. 先了解下WebSocket. 开源中国的介绍:http://www.oschina.net/p/websocket 百度百科的介绍:http://baike.baidu.com/link?url=yMTBVobtkp1E1a0wrRJlnEX