`
独自等待戈多
  • 浏览: 36271 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

WebSocket(13)和C#通信

阅读更多

(1)什么是WebSocket

WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。

在WebSocket API中,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。

优点:

   a、服务器与客户端之间交换的标头信息很小,大概只有2字节

   b、服务器可以主动传送数据给客户端

 

(2)WebSocket(13)握手

WebSocket握手由客户端发起,报文样例:

 

   GET /chat HTTP/1.1

   Host: server.example.com

   Upgrade: websocket

   Connection: Upgrade

   Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==

   Origin: http://example.com

   Sec-WebSocket-Protocol: chat, superchat

   Sec-WebSocket-Version: 13

 

这里Sec-WebSocket-Version表明版本号是13;注意Sec-WebSocket-Key,这是客户端发送的密钥,服务端需要对该密钥进行处理,反馈给客户端,客户端验证密钥正确后就开始通信,这之后该密钥就没用了。

服务端反馈样例:

 

   HTTP/1.1 101 Switching Protocols

   Upgrade: websocket

   Connection: Upgrade

   Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

   Sec-WebSocket-Protocol: chat

 

C#服务端首先提取Sec-WebSocket-Key的字符串,加上“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”(是一个固定的GUID),用SHA1计算哈希码,用base64加密,最终生成Sec-WebSocket-Accept的内容。握手代码:

 

private void handShake(byte[] recBytes, int recByteLength)
        {
            string recStr = Encoding.UTF8.GetString(recBytes, 0, recByteLength);
            string[] ss = recStr.Split(Environment.NewLine.ToCharArray());

            string key = ss[10].Replace("Sec-WebSocket-Key: ", "");
            key += "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
            SHA1 sha1 = SHA1.Create();
            byte[] sha1bytes = sha1.ComputeHash(Encoding.UTF8.GetBytes(key));
            string acceptStr = Convert.ToBase64String(sha1bytes);

            string sendStr = "HTTP/1.1 101 Switching Protocols" + NewLine +
                 "Upgrade: websocket" + NewLine +
                "Connection: Upgrade" + NewLine +
                "Sec-WebSocket-Accept: " + acceptStr + NewLine +
                "Sec-WebSocket-Protocol: chat" + NewLine + NewLine;
            client.Send(System.Text.Encoding.UTF8.GetBytes(sendStr));

            isHandshaked = true;
        }

 

(3)接收客户端数据

客户端调用send方法将字符窜发送到服务端。服务端要以二进制(bit)解析frame的前两个byte,过程如下:

   1byte

      1bit: frame-fin,x0表示该message后续还有frame;x1表示是message的最后一个frame

      3bit: 分别是frame-rsv1、frame-rsv2和frame-rsv3,通常都是x0

      4bit: frame-opcode,x0表示是延续frame;x1表示文本frame;x2表示二进制frame;x3-7保留给非控制frame;x8表示关闭连接;x9表示ping;xA表示pong;xB-F保留给控制frame

   2byte

      1bit: Mask,1表示该frame包含掩码;0,表示无掩码

      7bit、7bit+2byte、7bit+8byte: 7bit取整数值,若在0-125之间,则是负载数据长度;若是126表示,后两个byte取无符号16位整数值,是负载长度;127表示后8个byte,取64位无符号整数值,是负载长度

   3-6byte: 这里假定负载长度在0-125之间,并且Mask为1,则这4个byte是掩码

   7-end byte: 长度是上面取出的负载长度,包括扩展数据和应用数据两部分,通常没有扩展数据;若Mask为1,则此数据需要解码,解码规则为1-4byte掩码循环和数据byte做异或操作。

C#接收数据代码如下:

private bool recData(byte[] recBytes, int recByteLength)
        {
            if (recByteLength < 2)
                return false;

            bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧
            if (!fin)
            {
                Console.WriteLine("recData exception: 超过一帧"); // 超过一帧暂不处理
                return false;
            }

            bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码
            if (!mask_flag)
            {
                Console.WriteLine("recData exception: 没有Mask"); // 不包含掩码的暂不处理
                return false;
            }

            int payload_len = recBytes[1] & 0x7F; // 数据长度

            byte[] masks = new byte[4];
            byte[] payload_data;
            if (payload_len == 126)
            {
                Array.Copy(recBytes, 4, masks, 0, 4);
                payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]);
                payload_data = new byte[payload_len];
                Array.Copy(recBytes, 8, payload_data, 0, payload_len);
            }
            else if (payload_len == 127)
            {
                Array.Copy(recBytes, 10, masks, 0, 4);
                byte[] uInt64Bytes = new byte[8];
                for (int i = 0; i < 8; i++)
                {
                    uInt64Bytes[i] = recBytes[9 - i];
                }
                UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0);

                payload_data = new byte[len];
                for (UInt64 i = 0; i < len; i++)
                    payload_data[i] = recBytes[i + 14];
            }
            else
            {
                Array.Copy(recBytes, 2, masks, 0, 4);
                payload_data = new byte[payload_len];
                Array.Copy(recBytes, 6, payload_data, 0, payload_len);
            }

            for (var i = 0; i < payload_len; i++)
                payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]);

            string content = Encoding.UTF8.GetString(payload_data);
            Console.WriteLine("client: {0}", content);

            return true;
        }

 

(3)发送数据到客户端

服务器发送的数据以0x81开头,紧接发送内容的长度(若长度在0-125,则1个byte表示长度;若长度不超过0xFFFF,则后2个byte作为无符号16位整数表示长度;若超过0xFFFF,则后8个byte作为无符号64位整数表示长度),最后是内容的byte数组。

C#发送代码:

private void sendData(string content)
        {
            byte[] contentBytes = null;
            byte[] temp = Encoding.UTF8.GetBytes(content);
            if (temp.Length < 126)
            {
                contentBytes = new byte[temp.Length + 2];
                contentBytes[0] = 0x81;
                contentBytes[1] = (byte)temp.Length;
                Array.Copy(temp, 0, contentBytes, 2, temp.Length);
            }
            else if (temp.Length < 0xFFFF)
            {
                contentBytes = new byte[temp.Length + 4];
                contentBytes[0] = 0x81;
                contentBytes[1] = 126;
                contentBytes[2] = (byte)(temp.Length & 0xFF);
                contentBytes[3] = (byte)(temp.Length >> 8 & 0xFF);
                Array.Copy(temp, 0, contentBytes, 4, temp.Length);
            }
            else
            {
                // 暂不处理超长内容
            }

            client.Send(contentBytes);
        }

 

(4)html客户端代码

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>WebSocket</title>
    <script type="text/javascript">
        if (!window.WebSocket)
            alert("WebSocket not supported by this browser!");

        var ws;
        function connectWS() {
            if (ws == null) {
                ws = new WebSocket("ws://127.0.0.1:5001");
                ws.onmessage = function (evt) {
                    alert("接收到信息:" + evt.data);
                };

                ws.onclose = function () {
                    alert("连接已关闭。");
                    ws = null;
                };

                ws.onerror = function (evt) {
                    alert("连接出错:" + evt.data);
                    ws = null;
                }

                ws.onopen = function (evt) {
                    alert("连接已打开。");
                };
            }
        }
        function sendWS() {
            if (ws != null) {
                try {
                    var sendstr = document.getElementById("txtSend").value;
                    if (sendstr == "")
                        return;
                    ws.send(sendstr);
                } catch (err) {
                    alert(err.Data);
                }
            } else {
                alert("连接失效。");
            }
        }
        function closeWS() {
            ws.send("exit");
            ws.close();
        }
    </script>
</head>
<body style="text-align: center;">
    <input type="button" value="连接" onclick="connectWS()" />
    <input type="button" value="断开" onclick="closeWS()" />
    <br />
    <input type="text" id="txtSend" /><input type="button" id="btnSend" value="发送" onclick="sendWS()" />
</body>
</html>

 

附件是服务端代码,以及html测试网页

 

以上

分享到:
评论
2 楼 sanrenxing_1 2017-03-17  
我觉得这种东西自己开发太麻烦了,就别自己捣鼓了,找个第三方,方便,GoEasy就挺不错的,我昨天试了一下,代码简洁易懂,几分钟我就洗了一个自己的实时推送功能;官网: http://goeasy.io/
1 楼 qnfng 2012-08-23  
兄弟没成啊,握手失败!没反应啊

相关推荐

    C#实现WebSocket源码(c#写的服务端html写的客户端)

    C#实现WebSocket源码(c#写的服务端html写的客户端) WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。 它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器...

    c# winform快速建websocket客户端源码 wpf快速搭建websocket客户端 c#简单建立websocket

    WebSocket协议作为一种在单个TCP连接上进行全双工通信的技术,使得客户端和服务器之间能够进行低延迟、高效率的数据交换,非常适合于实时推送通知、在线聊天、游戏实时更新等场景。使用C# WinForm结合WebSocket...

    C#版Socket通信含服务端、客户端、WebSocket,代码完整清晰

    本项目包含了一个完整的C#版Socket通信示例,涵盖了服务端、客户端以及WebSocket的实现,对于学习和理解网络通信机制具有很高的参考价值。 首先,我们来详细探讨Socket的基本概念。Socket是网络通信的一种接口,它...

    C#WebSocket示例(初学者必备)

    WebSocket是一种在客户端和服务器之间建立长连接的协议,它提供了双向通信的能力,即服务器和客户端都可以主动发送数据。在Web开发中,WebSocket替代了传统的HTTP请求-响应模式,极大地提高了实时性,尤其适用于需要...

    C#_WinForm实现WebSocket及时通讯

    WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行双向通信,极大地提高了实时性。在IT行业中,尤其是在开发实时应用如聊天室、在线游戏或者股票交易系统时,WebSocket已经成为首选的通信技术...

    C# 开发 websocket 服务端和客户端

    在C#中开发WebSocket服务端和客户端,可以实现双向通信,即服务器和客户端都能主动发送数据,这对于实时性要求高的应用,如在线聊天、游戏、股票交易等场景非常适用。 WebSocketSharp是C#中的一个开源库,它为C#...

    c# winform快速建websocket服务器源码 wpf快速搭建websocket服务

    c# winform快速建websocket服务器源码 wpf快速搭建websocket服务 c#简单建立websocket服务 websocket快速搭建 ...本文将探讨WebSocket通信技术的优势,并阐述为何选择C#作为服务端开发语言的几大理由。

    C# mvc websocket 在线聊天实例

    WebSocket 是一种在客户端和服务器之间建立持久连接的协议,它允许双向通信,即服务器和客户端都可以主动发送数据。在C# MVC(Model-View-Controller)框架中集成WebSocket,可以创建实时、低延迟的在线聊天应用。...

    C#实现WebSocket协议客户端和服务器websocket sharp组件实例解析

    总结来说,WebSocket Sharp 提供了一个强大且灵活的工具,用于在C#环境中实现WebSocket协议,无论是构建实时交互的Web应用,还是在Unity游戏开发中实现网络通信,都是一个值得考虑的选择。通过理解和掌握其基本用法...

    WebSocketDemo(C#)

    总的来说,WebSocketDemo(C#)是一个学习和实践WebSocket协议以及SuperSocket框架的好例子。它展示了如何利用这些技术实现实时双向通信,这对于开发聊天应用、在线游戏、股票交易系统等需要实时数据交换的场景非常...

    C# WebSocket使用实例源码,包含服务端和客户端

    本实例是一个基于C#的WebSocket应用,包括服务端和客户端的源代码,适用于Visual Studio 2017开发环境。 首先,我们来看服务端部分。服务端通常是WebSocket通信的起点,它监听特定的端口,等待客户端的连接请求。在...

    C# WinForm客户端连接 WebSocket

    总结,通过结合C# WinForm的强大UI功能和WebSocket的实时通信能力,我们可以创建出高效的桌面应用。在VS2019中,利用WebSocket4Net库,我们可以轻松地实现客户端与WebSocket服务器之间的数据交换,从而满足各种实时...

    C# IIS webSocket 实例

    WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行双向通信,极大地提高了实时性。在IT行业中,尤其是在开发实时应用如在线聊天、股票交易、多人在线游戏等场景时,WebSocket已经成为首选的...

    C#WebSocket客户端及服务端Demo源代码

    WebSocket是Web应用中实现双向通信的一种技术,它允许服务器和客户端之间进行实时、低延迟的数据交换。在C#中,可以使用.NET Framework或.NET Core来实现WebSocket客户端和服务端的开发。下面将详细介绍C# WebSocket...

    C# VS MVC 下WebSocket简单应用

    WebSocket是Web通信协议的一种,它允许在客户端和服务器之间建立持久的、低延迟的双向连接。在C#和ASP.NET MVC框架下,WebSocket提供了一种高效的方式来进行实时数据交互,尤其适用于在线聊天、游戏、股票交易等需要...

    C# WinForm 通过WebSocket 实现文件传输示例

    总的来说,结合C# WinForm的用户交互能力和WebSocket的实时通信特性,可以构建出一个高效且用户友好的文件传输系统。在实际项目中,可能还需要考虑安全性问题,如数据加密、身份验证等,以保证文件传输的安全。这个...

    websocket的c#使用demo

    WebSocket是一种在客户端和服务器之间建立持久连接的协议,它允许双方进行全双工通信,即数据可以在两个方向上同时传输,极大地提高了实时性。在C#中,WebSocket的使用主要依赖于.NET Framework或.NET Core提供的...

    C# WebSocketSharp 框架的用法

    WebSocketSharp 是一个 C# 实现的 WebSocket 客户端和服务器框架,它为开发者提供了在 .NET 应用程序中实现 WebSocket 协议的强大工具。WebSocketSharp 允许你轻松地创建可以双向通信的实时应用,例如在线游戏、实时...

    WebSocket C#/ASP.NET 示例

    总的来说,这个"WebSocket C#/ASP.NET 示例"提供了一个实用的学习资源,演示了如何在ASP.NET MVC中集成WebSocket,利用C#和SuperWebSocket实现服务器与客户端之间的实时通信。对于想要提升Web应用实时性特性的开发者...

Global site tag (gtag.js) - Google Analytics