图片 19

JavaScript之WebSocket才干详解,WebSocket和Socket完结聊天群发

接受格局

既然使用WebSocket做协议当然接受就无须用socket而是利用WebSocket啦。通过在收受到请求后得到上下文中的WebSocket。

            //创建新WebSocket实例
            WebSocket myClientSocket = context.WebSocket;
            string userId = context.QueryString["userId"];

在这里大家有一些变通就是socke用户是透过socket随机获得的,这里小编修改成了页面传输。前台代码:

 var userId = parseInt(Math.random() * (999999 - 100000 + 1) + 100000, 10);
        console.log(userId)
        ws = new WebSocket('ws://' + window.location.hostname + ':' + window.location.port + '/socket?userId=' + userId);

然后,初叶与服务器创设连接(这里假定服务器就是本机的1740端口,须求利用ws协议)。

javascript代码

图片 1图片 2

function webSocketClose() {
    ws.close();
    alert("关闭了通讯")
}
//单聊
function send() {
    var msg = document.getElementById("message").value;
    var data = ""+document.getElementById("userId").value +","+ msg
    if (msg == "" || msg == undefined) {
        alert("请填写发送内容!")
        return;
    }
    ws.send(data);
}
//群发(所有用户)
function sendGroup() {
    var msg = document.getElementById("message").value;
    var data = "all," + msg
    if (msg == "" || msg == undefined) {
        alert("请填写发送内容!")
        return;
    }
    ws.send(data);
}
//群组发送A
function sendGroupA() {
    var msg = document.getElementById("message").value;
    var data = "groupA," + msg
    if (msg == "" || msg == undefined) {
        alert("请填写发送内容!")
        return;
    }
    ws.send(data);
}
//群组发送A
function sendGroupB() {
    var msg = document.getElementById("message").value;
    var data = "groupB," + msg
    if (msg == "" || msg == undefined) {
        alert("请填写发送内容!")
        return;
    }
    ws.send(data);
}

View Code

接受多少

WebSocket也未尝辜负大家的梦想,接受多少的管理也无需大家管理的,使用ReceiveAsync方法能够获得消息字节,大家只须求定义一个字节数组段用来接受就可以,比如:

                        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);//定义字节数组
                        WebSocketReceiveResult result = await myClientSocket.ReceiveAsync(buffer, CancellationToken.None);//获得字节
                        string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息

是还是不是感到越发的惠及,未有了那么些乱七捌糟的拍卖了。看着如故挺舒适的。

connection.send(message);
除此之外发送字符串,也能够利用 Blob 或 ArrayBuffer
对象发送贰进制数据。

群组完结

图片 3图片 4

#region 实现群组

        //群组记录分类
        List<GroupHelp> groupList = new List<GroupHelp>();
        public void GroupChatA(string groupName, string userId, string msg)
        {
            if (string.IsNullOrEmpty(groupName))
            {
                return;
            }
            //判断自己是否在群组
            GroupHelp isEisx = groupList.Where(b => b.userId == userId && b.Name == groupName).FirstOrDefault();
            if (isEisx == null)
            {
                groupList.Add(new GroupHelp()
                {
                    Name = groupName,
                    userId = userId
                });
            }
            //根据群组名称判断是否存在群组
            var nowGroupList = groupList.Where(b => b.Name == groupName).ToList();
            foreach (var itemG in nowGroupList)
            {
                Socket socket = ListUser[itemG.userId];
                try
                {
                    socket.Send(SendMsg($"用户({userId}=>{itemG.userId}):{msg}"));
                }
                catch (Exception e)
                {
                    Debug.WriteLine("该用户已掉线:" + itemG.userId);
                    //用户已掉线就删除掉
                    ListUser.Remove(itemG.userId);
                }
            }
        }
        #endregion

View Code

判读在线形式

WebSocket有独立的图景来开始展览在线的判别,不用大家协和写判定管理或然比较好的。

                            #region 关闭Socket处理,删除连接池
                            if (myClientSocket.State != WebSocketState.Open)//连接关闭
                            {
                                if (ListUser.ContainsKey(userId)) ListUser.Remove(userId);//删除连接池
                                break;
                            }
                            #endregion

请留意,WebSocket构和用ws表示。其它,还有wss协议,表示加密的WebSocket协议,对应HTTPs协议。
完了握手以往,WebSocket共商就在TCP协议之上,开端传送数据。

全总确定逻辑代码

此地是写在了服务端的音讯接受ReceiveMessage方法内,那个法子是叁个联合的出殡接受方法。想看原方法的请看上一篇:贯彻劳务端WebSocket传送门

自身那边只是写了自个儿要做的作用,当然能够友善无论修改的。

图片 5图片 6

 var resultStr = AnalyzeClientData(result, receiveNumber);
                    string[] resultList = resultStr.Split(',');
                    //string sendMsg = $"你({myClientSocket.RemoteEndPoint.ToString()}):" + resultList[1] + "【服务端回复】";
                    //myClientSocket.Send(SendMsg(sendMsg));//取消对自己提示发送给别人
                    if (string.IsNullOrEmpty(resultList[0]))
                    {
                        //退出                       
                        SignOut(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Remove(myClientSocket.RemoteEndPoint.ToString());
                        myClientSocket.Shutdown(SocketShutdown.Both);
                        myClientSocket.Close();
                        Debug.WriteLine("当前退出用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "login")
                    {
                        //登录
                        Login(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Add(myClientSocket.RemoteEndPoint.ToString(), myClientSocket);
                        Debug.WriteLine("当前登录用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "all")
                    {
                        //群发所有用户
                        GroupChat(myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else if (resultList[0] == "groupA")
                    {
                        //群组发送
                        GroupChatA("groupA", myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else if (resultList[0] == "groupB")
                    {
                        //群组发送
                        GroupChatA("groupB", myClientSocket.RemoteEndPoint.ToString(), resultList[1]);
                    }
                    else
                    {
                        //单聊
                        SingleChat(myClientSocket.RemoteEndPoint.ToString(), resultList[0], resultList[1]);
                    }

View Code

逻辑判别完毕就进来相应的事体方法了,上边我把每二个政工方法放上来。

写在始发

下边壹篇写了壹篇使用WebSocket做客户端,然后服务端是socke代码达成的。传送门:webSocket和Socket达成聊天群发

当然小编是打算写到一章上的,毕竟落成的都以同等的成效,后来想了想就没写在联合具名,首就算七个地点,

叁个缘故是那是另一种落成劳务章程,放在一同望着有点乱。单独写也便于查阅。贰是写是分手写的回家早晨写一些,不能够间接在原来的小说上写,就再一次起来1个文稿,但是写完就感到微微懒,不想结合到壹块了。嘿嘿,,,

从而对始发说的不精晓的同窗能够先看一下前方的事物。看一下基础,一举两得哦。

这1篇不做作用的更换,既然大家使用了WebSocket为何不应用到底哪,笔者不希罕socket的内部出现的卷入请求连接数据管理和发送数据管理。可以未有反常态呀。那您承接往下看吗。

率先WebSocket服务器那篇大家照旧促成的四个职能:

  • 单聊:能够内定人开始展览聊天。
  • 群发:那几个的情趣正是方今服务器内的全体人包括自身,那几个就跟叁个推送效果同样。
  • 开启连接(客户端):通告除本人以外的具备用户
  • 闭馆连接(客户端):通知除本人以外的具备用户
  • 群组A:落成一个群组名叫A
  • 群组B:完毕一个群组名为B

服务器端需求独自安顿管理WebSocket的代码。上面用node.js搭建三个服务器碰到。

翻开连接

图片 7图片 8

#region  登录提示别人
        public void Login(string userId)
        {
            if (ListUser.Count() > 0)
            {
                foreach (var item in ListUser)
                {
                    if (item.Key != userId)
                    {
                        Socket socket = item.Value;
                        try
                        {
                            socket.Send(SendMsg($"用户({userId})登录了"));
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("该用户已掉线:" + item.Key);
                            //用户已掉线就删除掉
                            ListUser.Remove(item.Key);
                        }
                    }
                }

            }

        }
        #endregion

View Code

入口函数

貌似处理程序中决断只接受WebSocket商业事务连接进入的运作:

            if (context.IsWebSocketRequest)
            {
                context.AcceptWebSocketRequest(Accept);
            }
            else
            {

            }

第一步,在劳务器端的连串根目录下,安装socket.io模块。

单聊

图片 9图片 10

#region 单聊
        public void SingleChat(string userIdA, string userIdB, string msg)
        {
            Socket socket = ListUser[userIdB];
            if (socket != null)
            {
                try
                {
                    socket.Send(SendMsg($"用户({userIdA}=>{userIdB}):{msg}"));
                }
                catch (Exception e)
                {
                    Debug.WriteLine("该用户已掉线:" + userIdB);
                    //用户已掉线就删除掉
                    ListUser.Remove(userIdB);
                }
            }

        }
        #endregion

View Code

 传送门:

基本功版本落成简单的websocket:达成劳务端webSocket连接通信

到家websocket完结聊天示例:WebSocket和Socket达成聊天群发

最后在送上github源码:

HTTP协议是1种无状态协议,服务器端自己不享有识别客户端的才干,必须借助外部体制,比方session和cookie,才具与一定客户端保持对话。那多有个别少带来一些困难,尤其在劳务器端与客户端必要持续交流数据的场子(比方网络聊天),更是如此。为了化解这么些题目,HTML5提议了浏览器的WebSocket
API。

群发全体人

图片 11图片 12

#region 群发
        public void GroupChat(string userId, string msg)
        {
            if (ListUser.Count() > 0)
            {
                foreach (var item in ListUser)
                {
                    if (item.Key != userId)
                    {
                        Socket socket = item.Value;
                        try
                        {
                            socket.Send(SendMsg($"用户({userId}=>{item.Key}):{msg}"));
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("该用户已掉线:" + item.Key);
                            //用户已掉线就删除掉
                            ListUser.Remove(item.Key);
                        }
                    }
                }

            }

        }
        #endregion

View Code

 单聊达成

此地本身就不把写的享有单聊,群里,达成群组方法贴上来了,达成的笔触依然和从前同样,只是写法不相同,小编就写四个单聊作为象征示例贴上来。想看1切在上边下载源码就好了。

 #region 单聊
        public void SingleChat(string userIdA, string userIdB, string msg)
        {
            WebSocket socket = ListUser[userIdB];
            if (socket != null)
            {
                if (socket != null && socket.State == WebSocketState.Open)
                {
                    ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"用户({userIdA}=>{userIdB}):{msg}"));
                    socket.SendAsync(buffer, WebSocketMessageType.Binary, true, CancellationToken.None);
                }
            }

        }
        #endregion

最后,用emit方法向劳动器端发送时域信号,触发服务器端的anotherNews事件。

 起初撸代码(socket版)

因为是在上头说道的篇章改换的,全部中央的三连击(开启服务,开启监听,接受事件)笔者就不介绍了。

 敬上代码

WebSocket不利用HTTP协议,而是选择自身的协商。浏览器发出的WebSocket请求类似于上面包车型客车楷模:

写在最后

以此正是本身不是基于seesion来打开判别用户的,全部每当刷新了页面也就约等于脱离了近来用户,仍旧要求重新开启连接的,那正是三个基本思路达成。还有待健全和不足。还请见谅。代码基本就诸多了。

源码放在了gitHub:

基础版本落成轻便的websocket:福衢寿车服务端webSocket连接通讯

劳动版本socket改为websocket完成版本:WebSocket和Socket落成聊天群发

技术点

前端写法都以同等的自个儿就不做过多的描述了,这里只假若针对性socket协议的办法实行修改成WebSocket格局。

首先本身本次是把劳动写成了貌似管理程序实行挂载的。(有个别有性障碍的青年人伴想改访问路由路线能够参考一下:mvc中路由的炫丽和得以达成IHttpHandler挂载

本身在本示例正是把位于model下的一个形似处理程序,改写成了socket路线.

原先访问是:http“//

改完事后是:http“//

在骨子里项目中能够不揭发文件的就是路线地方,还是有点用处的。

不得不说WebSocket确实不错,举个例子收受发送数据解析方法都给封装好了。

第二步,在根目录下创设app.js,并写入以下代码(假定使用了Express框架)。

 数据管理方法

图片 13图片 14

  #region 打包请求连接数据
        /// <summary>
        /// 打包请求连接数据
        /// </summary>
        /// <param name="handShakeBytes"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private byte[] PackageHandShakeData(byte[] handShakeBytes, int length)
        {
            string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, length);
            string key = string.Empty;
            Regex reg = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
            Match m = reg.Match(handShakeText);
            if (m.Value != "")
            {
                key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
            }
            byte[] secKeyBytes = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
            string secKey = Convert.ToBase64String(secKeyBytes);
            var responseBuilder = new StringBuilder();
            responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + "\r\n");
            responseBuilder.Append("Upgrade: websocket" + "\r\n");
            responseBuilder.Append("Connection: Upgrade" + "\r\n");
            responseBuilder.Append("Sec-WebSocket-Accept: " + secKey + "\r\n\r\n");
            return Encoding.UTF8.GetBytes(responseBuilder.ToString());
        }
        #endregion

        #region 处理接收的数据
        /// <summary>
        /// 处理接收的数据
        /// 参考 http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html
        /// </summary>
        /// <param name="recBytes"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        private string AnalyzeClientData(byte[] recBytes, int length)
        {
            int start = 0;
            // 如果有数据则至少包括3位
            if (length < 2) return "";
            // 判断是否为结束针
            bool IsEof = (recBytes[start] >> 7) > 0;
            // 暂不处理超过一帧的数据
            if (!IsEof) return "";
            start++;
            // 是否包含掩码
            bool hasMask = (recBytes[start] >> 7) > 0;
            // 不包含掩码的暂不处理
            if (!hasMask) return "";
            // 获取数据长度
            UInt64 mPackageLength = (UInt64)recBytes[start] & 0x7F;
            start++;
            // 存储4位掩码值
            byte[] Masking_key = new byte[4];
            // 存储数据
            byte[] mDataPackage;
            if (mPackageLength == 126)
            {
                // 等于126 随后的两个字节16位表示数据长度
                mPackageLength = (UInt64)(recBytes[start] << 8 | recBytes[start + 1]);
                start += 2;
            }
            if (mPackageLength == 127)
            {
                // 等于127 随后的八个字节64位表示数据长度
                mPackageLength = (UInt64)(recBytes[start] << (8 * 7) | recBytes[start] << (8 * 6) | recBytes[start] << (8 * 5) | recBytes[start] << (8 * 4) | recBytes[start] << (8 * 3) | recBytes[start] << (8 * 2) | recBytes[start] << 8 | recBytes[start + 1]);
                start += 8;
            }
            mDataPackage = new byte[mPackageLength];
            for (UInt64 i = 0; i < mPackageLength; i++)
            {
                mDataPackage[i] = recBytes[i + (UInt64)start + 4];
            }
            Buffer.BlockCopy(recBytes, start, Masking_key, 0, 4);
            for (UInt64 i = 0; i < mPackageLength; i++)
            {
                mDataPackage[i] = (byte)(mDataPackage[i] ^ Masking_key[i % 4]);
            }
            return Encoding.UTF8.GetString(mDataPackage);
        }
        #endregion

        #region 发送数据
        /// <summary>
        /// 把发送给客户端消息打包处理(拼接上谁什么时候发的什么消息)
        /// </summary>
        /// <returns>The data.</returns>
        /// <param name="message">Message.</param>
        private byte[] SendMsg(string msg)
        {
            byte[] content = null;
            byte[] temp = Encoding.UTF8.GetBytes(msg);
            if (temp.Length < 126)
            {
                content = new byte[temp.Length + 2];
                content[0] = 0x81;
                content[1] = (byte)temp.Length;
                Buffer.BlockCopy(temp, 0, content, 2, temp.Length);
            }
            else if (temp.Length < 0xFFFF)
            {
                content = new byte[temp.Length + 4];
                content[0] = 0x81;
                content[1] = 126;
                content[2] = (byte)(temp.Length & 0xFF);
                content[3] = (byte)(temp.Length >> 8 & 0xFF);
                Buffer.BlockCopy(temp, 0, content, 4, temp.Length);
            }
            return content;
        }
        #endregion

View Code

发送数据

既然如此接受多少都有独立的章程封装,发送新闻尚未道理平昔不的,是的出殡和埋葬使用SendAsync方法,使用格局和ReceiveAsync类似,首先定义一个字节数组段用来存放内容,举例:

                        ArraySegment<byte> buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes($"用户({userIdA}=>{userIdB}):{msg}"));
                        socket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);

那标准便是二个出殡和埋葬进度,先把要发送的字符串转换到字节数组段,然后把这些数组段使用SendAsync发送出去就能够了。

 注:在上头的多少个办法中咱们都看到了ArraySegment这一个东西,他到底是个什么样哪,他是3个命名在System命名空间下的贰个结构体。类似与Array数组然则他又不是数组,为啥那样说,因为她还行数组段,他得以只保留内容中的一局地而不是壹体。就如外人说的小抽斗同样。笔者是把他驾驭成先把她放到这里当做数据缓存区,等实际发送的时候实行发送数据。WebSocketMessageType是二个枚举类型,通过F1二能够看看:

    // 摘要:
    //     指示消息类型:
    public enum WebSocketMessageType
    {
        //
        // 摘要:
        //     该消息是明文形式。
        Text = 0,
        //
        // 摘要:
        //     消息采用二进制格式。
        Binary = 1,
        //
        // 摘要:
        //     因为收到关闭的消息,接受已完成。
        Close = 2
    }

最终,监听用户的disconnect事件。

关闭连接

图片 15图片 16

#region  退出提示别人
        public void SignOut(string userId)
        {
            if (ListUser.Count() > 0)
            {
                foreach (var item in ListUser)
                {
                    if (item.Key != userId)
                    {
                        Socket socket = item.Value;
                        try
                        {
                            socket.Send(SendMsg($"用户({userId})退出了"));
                        }
                        catch (Exception e)
                        {
                            Debug.WriteLine("该用户已掉线:" + item.Key);
                            //用户已掉线就删除掉
                            ListUser.Remove(item.Key);
                        }
                    }
                }

            }

        }
        #endregion

View Code

音信管理

上面正是允许连接后的显要方法,类似上壹篇写的ReceiveMessage方法(接受音讯),这里的拍卖存在一些改成,所以自个儿就把装有代码贴上来了。

 1 #region 处理客户端连接请求
 2         /// <summary>
 3         /// 处理客户端连接请求
 4         /// </summary>
 5         /// <param name="result"></param>
 6         private async Task Accept(AspNetWebSocketContext context)
 7         {
 8             //创建新WebSocket实例
 9             WebSocket myClientSocket = context.WebSocket;
10             string userId = context.QueryString["userId"];
11 
12             try
13             {
14 
15                 string descUser = string.Empty;//目的用户
16                 while (true)
17                 {
18                     if (myClientSocket.State == WebSocketState.Open)
19                     {
20                         ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
21                         WebSocketReceiveResult result = await myClientSocket.ReceiveAsync(buffer, CancellationToken.None);
22 
23                         #region 消息处理(字符截取、消息转发)
24                         try
25                         {
26                             #region 关闭Socket处理,删除连接池
27                             if (myClientSocket.State != WebSocketState.Open)//连接关闭
28                             {
29 
30                                 if (ListUser.ContainsKey(userId))
31                                 {
32                                     //退出                       
33                                     SignOut(userId);
34                                     ListUser.Remove(userId);//删除连接池
35                                     Debug.WriteLine("当前退出用户:" + userId);
36                                 }
37                                 break;
38                             }
39                             #endregion
40                             string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
41                             string[] resultList = userMsg.Split(',');
42                             if (resultList[0] == "login")
43                             {
44                                 //登录
45                                 Login(userId);
46                                 #region 用户添加连接池
47                                 //第一次open时,添加到连接池中
48                                 if (!ListUser.ContainsKey(userId))
49                                     ListUser.Add(userId, myClientSocket);//不存在,添加
50                                 else
51                                     if (myClientSocket != ListUser[userId])//当前对象不一致,更新
52                                     ListUser[userId] = myClientSocket;
53                                 #endregion
54                                 Debug.WriteLine("当前登录用户:" + userId);
55                             }
56                             else if (resultList[0] == "all")
57                             {
58                                 //群发所有用户
59                                 GroupChat(userId, resultList[1]);
60                             }
61                             else if (resultList[0] == "groupA")
62                             {
63                                 //群组发送
64                                 GroupChatA("groupA", userId, resultList[1]);
65                             }
66                             else if (resultList[0] == "groupB")
67                             {
68                                 //群组发送
69                                 GroupChatA("groupB", userId, resultList[1]);
70                             }
71                             else
72                             {
73                                 //单聊
74                                 SingleChat(userId, resultList[0], resultList[1]);
75                             }
76 
77                         }
78                         catch (Exception exs)
79                         {
80                             //消息转发异常处理,本次消息忽略 继续监听接下来的消息
81                         }
82                         #endregion
83                     }
84                     else
85                     {
86                         break;
87                     }
88                 }//while end
89             }
90             catch (Exception ex)
91             {
92                 Console.WriteLine("Error : " + ex.ToString());
93             }
94         }
95         #endregion

下一场,在客户端脚本中,建设构造WebSocket连接。

思路分析

咱俩既是达成的是聊天,那么跟哪个人聊天当然是其余人,所以大家应当有别的人,但是难点又来了笔者们登六了怎么样确认记录状态哪,作者报到之后小编得以跟服务器通讯,怎么找到其余人实行报纸发表哪?笔者固然想到的是利用字典Dictionary来进展仓库储存,为何用字典而不用list是因为,字典中是键值积累,大家把键当作人,然后值存款和储蓄这厮的报纸发表连接,那样自身倘使领会这厮就在内部找到这厮,然后就取到此人的接连就可以通信了。

        //建立登录用户记录信息
        public static Dictionary<string, Socket> ListUser = new Dictionary<string, Socket>();

注:写完那一个现在我们十一分看了下本人的代码说你这些存在3个标题:线程安全,确实的Dictionary不是线程安全,当时写的时候没多想,他说完自个儿就想起来了,从前用Paralle时候利用的线程安全类ConcurrentBag和ConcurrentDictionary,在那了本来能够改成:

       //建立登录用户记录信息
        public static ConcurrentDictionary<string, Socket> ListUser = new ConcurrentDictionary<string, Socket>();

好了我们能够进行电视发表了,可以找到钦定的人实行电视发表了,那自然全体人的简报也得以化解了。全部小编就一向说下展开连接和关闭连接的通报。我在音信接受和音讯发送的时候定义了上下一心的平整:

翻开连接:小编在出殡和埋葬的时候最前头带:login字符串告诉音信接受小编明天是登陆,你告诉外人吧。

关门连接:退出的时候从不发送字符串所感到空

 ws.send("login,我已经连接上了!!!");

  ws.close();
  alert(“关闭了电视发表”)

下一场本人在音信管理扩大了剖断管理:

                   if (string.IsNullOrEmpty(resultList[0]))
                    {
                        //退出                       
                        SignOut(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Remove(myClientSocket.RemoteEndPoint.ToString());
                        myClientSocket.Shutdown(SocketShutdown.Both);
                        myClientSocket.Close();
                        Debug.WriteLine("当前退出用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }
                    else if (resultList[0] == "login")
                    {
                        //登录
                        Login(myClientSocket.RemoteEndPoint.ToString());
                        ListUser.Add(myClientSocket.RemoteEndPoint.ToString(), myClientSocket);
                        Debug.WriteLine("当前登录用户:" + myClientSocket.RemoteEndPoint.ToString());
                    }

大致其余的笔触也是以此样子:单聊,群发,群组都以概念相应的规则来拓展判别然后实行单独的事务。

server.listen(1740, function() {

 console.log((new Date()) + ' Server is listening on port 1740');

});

介绍:

眼下写过壹篇轻松的websocke落成服务端。那1篇就不在说什么样基础的事物主倘诺来用实例说话,重若是讲一下兑现单聊和群组聊天和全数群发的思路设计。

直接不懂的能够看一下上1篇简单版本再来看也行:金镶玉裹福禄双全服务端WebSocket传送门

你只怕感兴趣的小说:

  • 详解WebSocket+spring示例demo(已使用sockJs库)
  • 依赖html五和nodejs相结合贯彻websocket尽管通信
  • 浅析nodejs达成Websocket的多少接收与发送
  • Python通过websocket与js客户端通讯示例分析
  • Javascript
    WebSocket使用实例介绍(简明入门教程)
  • JS落成websocket长轮询实时音信提醒的职能

兑现效益:

本示例首要落成了个什么东西哪,大家都施用qq只怕别的的聊天工具,全部上面笔者说的豪门也都懂。就不啰嗦废话了。

第3说达成5个主要的法力:

  • 单聊:能够钦赐人张开聊天。
  • 群发:这么些的乐趣正是近年来服务器内的全部人包罗本人,这些就跟二个推送效果同样。
  • 张开连接(客户端):文告除自身以外的保有用户
  • 关闭连接(客户端):文告除自身以外的享有用户
  • 群组A:落成二个群组名叫A
  • 群组B:落成2个群组名称叫B

好了着力就是以此大要功用。上边看下最后效果呢:

图片 17图片 18图片 19

以上是首先个图先进入了A群组,前边多少个在B群组。然后A有进入了B群组,全部第3张图能够接过全数聊天,可是前边两张只可以吸收B群组的闲聊。

Socket.io简介

connection.binaryType = 'arraybuffer';

connection.onmessage = function(e) {
 console.log(e.data.byteLength); // ArrayBuffer对象有byteLength属性
};

connection.onopen = wsOpen;

var http = require('http');

var server = http.createServer(function(request, response) {});
connection.on('close', function(reasonCode, description) {

 console.log(connection.remoteAddress + ' disconnected.');

});

概述

***建设构造连接和断开连接
发送数据和接收数据
管理错误

connection.onmessage = wsMessage;

请留意,emit方法能够替代Ajax请求,而on方法钦点的回调函数,也同等Ajax的回调函数。
第四步,在服务器端的app.js,出席以下代码。

if(window.WebSocket != undefined) {

 // WebSocket代码

}

客户端收到服务器发送的数额,会触发message事件。能够由此定义message事件的回调函数,来拍卖服务端再次来到的多寡。

WebSocket和睦完全能够代替Ajax方法,用来向服务器端发送文书和贰进制数据,而且还未曾“同域限制”。

服务器端的WebSocket回应则是

wsServer.on(‘request', function(r){

 connection = req.accept(‘echo-protocol', req.origin);



connection.on('message', function(message) {
 var msgString = message.utf8Data;
 connection.sendUTF(msgString);
});
});

var connection;
wsServer.on(‘request’, function(req){

connection.onerror = wsError;

connection.onclose = wsClose;

io.sockets.on('connection', function (socket) {
 socket.emit('news', { hello: 'world' });
 socket.on('anotherNews', function (data) {
 console.log(data);
 });
});

地点代码的回调函数接受2个参数req,表示request请求对象。然后,在回调函数内部,创立WebSocket连接connection。接着,就要对connection的message事件内定回调函数。

服务器端

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);

server.listen(80);

app.get('/', function (req, res) {
 res.sendfile(__dirname + '/index.html');
});
if(window.WebSocket != undefined) {

 var connection = new WebSocket('ws://localhost:1740');

}

如上就是本文的全体内容,希望对大家的读书抱有帮助,也指望我们多多帮助脚本之家。

制造连接以往的WebSocket实例对象(即上面代码中的connection),有二个readyState属性,表示近期的气象,能够取6个值:

上边代码表示,先创设并运维HTTP服务器。Socket.io的周转创建在HTTP服务器之上。

var WebSocketServer = require('websocket').server;

var wsServer = new WebSocketServer({

 httpServer: server

});

出于本例假定WebSocket主机与客户端是同壹台机械,所以connect方法的参数是

浏览器端对WebSocket商量的管理,无非正是3件事:

WebSocket商业事务要求服务器协理,最近可比盛行的得以落成是依附node.js的socket.io,更加多的落成可参考Wikipedia。至于浏览器端,方今主流浏览器都支持WebSocket商量(包罗IE
10+),仅有的例外是手提式有线电话机端的Opera Mini和Android Browser。

0: 正在连接
1: 连接成功
二: 正在关闭
叁: 连接关闭
拉手球组织议成功以往,readyState就从0变为一,并触发open事件,那时就足以向服务器发送新闻了。我们能够钦赐open事件的回调函数。

WebSocket服务器创立request事件的回调函数。

上面代码的io.sockets.on方法钦赐connection事件(WebSocket连接创立)的回调函数。在回调函数中,用emit方法向客户端发送数据,触发客户端的news事件。然后,再用on方法钦点服务器端anotherNews事件的回调函数。

随后运营WebSocket服务器。那需求加载websocket库,如果未有安装,能够先利用npm命令安装。

第三步,将Socket.io插入客户端网页。

第三,客户端要检查浏览器是或不是扶助WebSocket,使用的不2诀假诺查看window对象是或不是持有WebSocket属性。

管理错误

<script
src=”/socket.io/socket.io.js”></script>


function wsOpen (event) { 
console.log(‘Connected to: ‘ + event.currentTarget.URL); 
}
socket.on('news', function (data){
 console.log(data);
});

固然接收的是2进制数据,供给将延续对象的格式设为blob或arraybuffer。

WebSocket的重中之重作用是,允许服务器端与客户端进行全双工(full-duplex)的通信。比方来讲,HTTP协议有点像发电子邮件,发出后务必等待对方回信;WebSocket则是像打电话,服务器端和客户端可以而且向对方发送数据,它们之间存着一条持续展开的数据通道。

var socket =
io.connect(”);

function wsMessage (event) { 
console.log(event.data); 
}

倘若出现谬误,浏览器会触发WebSocket实例对象的error事件。

创建连接和断开连接

三番五次创立后,客户端通过send方法向劳动器端发送数据。

GET / HTTP/1.1
Connection: Upgrade
Upgrade: websocket
Host: example.com
Origin: null
Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==
Sec-WebSocket-Version: 13
下面的头消息突显,有贰个HTTP头是Upgrade。HTTP一.一说道鲜明,Upgrade头消息表示将通信协议从HTTP/1.一倒车该项所钦点的商业事务。“Connection:
Upgrade”就象征浏览器文告服务器,若是能够,就晋级到webSocket切磋。Origin用于声明浏览器域名是还是不是在服务器许可的限制内。Sec-WebSocket-Key则是用于握手球组织议的密钥,是base64编码的1六字节随机字符串。

function wsError(event) { 
console.log(“Error: “ + event.data); 
}

应用ws模块,计划一个简约的WebSocket服务器至极轻松。

socket.emit(‘anotherNews’);

关闭WebSocket连接,会触发close事件。

客户端

connection = req.accept(‘echo-protocol', req.origin); 
});

$ npm install socket.io

劳务器端同样用“Connection:
Upgrade”通告浏览器,必要退换协议。Sec-WebSocket-Accept是服务器在浏览器提供的Sec-WebSocket-Key字符串后边,增添“25八EAFA伍-E914-四7DA-95CA-C五AB0DC八五B11”
字符串,然后再取sha-一的hash值。浏览器将对这几个值举办认证,以注脚的确是目的服务器回应了webSocket请求。Sec-WebSocket-Location表示实行通讯的WebSocket网站。

function wsClose () { 
console.log(“Closed”); 
}

connection.close();

地点代码的回调函数wsMessage的参数为事件目标event,该目的的data属性包蕴了服务器重返的数目。

HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=
Sec-WebSocket-Origin: null
Sec-WebSocket-Location: ws://example.com/

// 使用ArrayBuffer发送canvas图像数据

var img = canvas_context.getImageData(0, 0, 400, 320);

var binary = new Uint8Array(img.data.length);

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

 binary[i] = img.data[i];

}

connection.send(binary.buffer);
// 使用Blob发送文件 
var file = document.querySelector(‘input[type=”file”]').files[0]; 
connection.send(file);
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({ port: 8080 });

wss.on('connection', function connection(ws) {
 ws.on('message', function incoming(message) {
 console.log('received: %s', message);
 });

 ws.send('something');
});

发送数据和接收数据

Socket.io是当前最盛行的WebSocket落成,包蕴服务器和客户端七个部分。它不只简化了接口,使得操作更便于,而且对于那个不帮衬WebSocket的浏览器,会活动降为Ajax连接,最大限度地确认保证了包容性。它的靶子是联合通讯机制,使得全数浏览器和移动设备都得以开始展览实时通讯。

无论是是服务器照旧客户端,socket.io提供三个焦点措施:emit方法用于发送信息,on方法用于监听对方发送的音信。

要是监听1740端口。