首页 > 其他分享 >【整理】html5知识点5

【整理】html5知识点5

时间:2023-05-22 13:38:30浏览次数:43  
标签:知识点 WebSocket string ws html5 整理 Sec byte 客户端

============================================HTML5 WebSocket



 什么是websocket



  WebSocket 协议是html5引入的一种新的协议,其目的在于实现了浏览器与服务器全双工通信。看了上面链接的同学肯定对过去怎么低效率高消耗(轮询或comet)的做此事已经有所了解了,而在websocket API,浏览器和服务器只需要要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。同时这么做有两个好处



 1.通信传输字节减少:比起以前使用http传输数据,websocket传输的额外信息很少,据百度说只有2k



 2.服务器可以主动向客户端推送消息,而不用客户端去查询



 握手



  除了TCP连接的三次握手,websocket协议中客户端与服务器想建立连接需要一次额外的握手动作,在最新版的协议中是这个样子的



 客户端向服务器发送请求



 GET / HTTP/1.1

 Upgrade: websocket

 Connection: Upgrade

 Host: 127.0.0.1:8080

 Origin: http://test.com

 Pragma: no-cache

 Cache-Control: no-cache

 Sec-WebSocket-Key: OtZtd55qBhJF2XLNDRgUMg==

 Sec-WebSocket-Version: 13

 Sec-WebSocket-Extensions: x-webkit-deflate-frame

 User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.57 Safari/537.36

 服务器给出响应



 HTTP/1.1 101 Switching Protocols

 Upgrade: websocket

 Connection: Upgrade

 Sec-WebSocket-Accept: xsOSgr30aKL2GNZKNHKmeT1qYjA=



  在请求中的“Sec-WebSocket-Key”是随机的,服务器端会用这些数据来构造出一个SHA-1的信息摘要。把“Sec-WebSocket-Key”加上一个魔幻字符串“258EAFA5-E914-47DA-95CA-C5AB0DC85B11”。使用 SHA-1 加密,之后进行 BASE-64编码,将结果做为 “Sec-WebSocket-Accept” 头的值,返回给客户端



 websocket API



 经过握手之后浏览器与服务器建立连接,两者就可以互相通信了。websocket的API真心很简单,看看 W3C 的定义



 tring url, optional (DOMString or DOMString[]) protocols)]

 interface WebSocket : EventTarget {

   readonly attribute DOMString url;



   // ready state

   const unsigned short CONNECTING = 0;

   const unsigned short OPEN = 1;

   const unsigned short CLOSING = 2;

   const unsigned short CLOSED = 3;

   readonly attribute unsigned short readyState;

   readonly attribute unsigned long bufferedAmount;



   // networking

            attribute EventHandler onopen;

            attribute EventHandler one rror;

            attribute EventHandler onclose;

   readonly attribute DOMString extensions;

   readonly attribute DOMString protocol;

   void close([Clamp] optional unsigned short code, optional DOMString reason);



   // messaging

            attribute EventHandler onmessage;

            attribute BinaryType binaryType;

   void send(DOMString data);

   void send(Blob data);

   void send(ArrayBuffer data);

   void send(ArrayBufferView data);

 };



 ==================================================

 创建websocket



 ws=new WebSocket(address); //ws://127.0.0.1:8080

 调用其构造函数,传入地址,就可以创建一个websocket了,值得注意的是地址协议得是ws/wss



 关闭socket



 ws.close();

 调用webservice实例的close()方法就可以关闭webservice,当然也可以传入一个code和string说明为什么关了



 几个回调函数句柄



 由于其异步执行,回调函数自然少不了,有四个重要的



 onopen:连接创建后调用

 onmessage:接收到服务器消息后调用

 one rror:出错时调用

 onclose:关闭连接的时候调用

 看名字就知道是干什么的了,每个回调函数都会传入一个Event对象,可以通过event.data访问消息



 使用API



 我们可以在创建socket成功后为其回调函数赋值



 ws=new WebSocket(address);

             ws.onopen=function(e){

                 var msg=document.createElement('div');

                 msg.style.color='#0f0';

                 msg.innerHTML="Server > connection open.";

                 msgContainer.appendChild(msg);

                 ws.send('{<'+document.getElementById('name').value+'>}');

             };

  也可以通过事件绑定的方式



 ws=new WebSocket(address);

             ws.addEventListener('open',function(e){

                 var msg=document.createElement('div');

                 msg.style.color='#0f0';

                 msg.innerHTML="Server > connection open.";

                 msgContainer.appendChild(msg);

                 ws.send('{<'+document.getElementById('name').value+'>}');

             });

 ============================================================================

 客户端实现



 其实客户端的实现比较简单,除了websocket相关的几句就是一些自动focus、回车键事件处理、消息框自动定位到底部等简单功能,不一一说明了



 【demo】已验证

 页面

 <!DOCTYPE html>

 <html>

 <head>

     <title></title>

     <script type="text/javascript">

         var ws;

         function ToggleConnectionClicked() {

             try {

                 var SOCKECT_ADDR = "ws://localhost:1818/chat";

                 ws = new WebSocket(SOCKECT_ADDR);
  



                 ws.onopen = function (event) { alert("已经与服务器建立了连接\r\n当前连接状态:" + this.readyState); };

                 ws.onmessage = function (event) { alert("接收到服务器发送的数据:\r\n" + event.data); };

                 ws.onclose = function (event) { alert("已经与服务器断开连接\r\n当前连接状态:" + this.readyState); };

                 ws.onerror = function (event) {alert("WebSocket异常!" + event.toString());};

             } catch (ex) {

                 alert(ex.message);

             }

         };



         function SendData() {

             try {

                 ws.send("success");

             } catch (ex) {

                 alert(ex.message);

             }

         };



         function seestate() {

             alert(ws.readyState);

         }

        

     </script>

 </head>

 <body>

     <button id='ToggleConnection' type="button" οnclick='ToggleConnectionClicked();'>

         连接服务器</button><br />

     <br />

     <button id='ToggleConnection' type="button" οnclick='SendData();'>

         发送我的名字:beston</button><br />

     <br />

     <button id='ToggleConnection' type="button" οnclick='seestate();'>

         查看状态</button><br />

     <br />

 </body>

 </html>



 服务器端控制台程序

 using System;

 using System.Text;

 using System.Net;

 using System.Net.Sockets;

 using System.Text.RegularExpressions;

 using System.Security.Cryptography;



 namespace WebSocketServer

 {

     class Program

     {

         static void Main(string[] args)

         {

             int port = 1818;

             byte[] buffer = new byte[1024];



             IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);

             Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);



             try

             {

                 listener.Bind(localEP);

                 listener.Listen(10);



                 Console.WriteLine("等待客户端连接....");

                 Socket sc = listener.Accept();//接受一个连接

                 Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接....");



                 //握手

                 int length = sc.Receive(buffer);//接受客户端握手信息

                 sc.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length)));

                 Console.WriteLine("已经发送握手协议了....");



                 //接受客户端数据

                 Console.WriteLine("等待客户端数据....");

                 length = sc.Receive(buffer);//接受客户端信息

                 string clientMsg = AnalyticData(buffer, length);

                 Console.WriteLine("接受到客户端数据:" + clientMsg);



                 //发送数据

                 string sendMsg = "您好," + clientMsg;

                 Console.WriteLine("发送数据:“" + sendMsg + "” 至客户端....");

                 sc.Send(PackData(sendMsg));



                 Console.WriteLine("演示Over!");

                 Console.Read();

             }

             catch (Exception e)

             {

                 Console.WriteLine(e.ToString());

             }



         }



         /// <summary>

         /// 打包握手信息

         /// </summary>

         /// <param name="secKeyAccept">Sec-WebSocket-Accept</param>

         /// <returns>数据包</returns>

         private static byte[] PackHandShakeData(string secKeyAccept)

         {

             var responseBuilder = new StringBuilder();

             responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine);

             responseBuilder.Append("Upgrade: websocket" + Environment.NewLine);

             responseBuilder.Append("Connection: Upgrade" + Environment.NewLine);

             responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine);

             //如果把上一行换成下面两行,才是thewebsocketprotocol-17协议,但居然握手不成功,目前仍没弄明白!

             //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine);

             //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine);



             return Encoding.UTF8.GetBytes(responseBuilder.ToString());

         }



         /// <summary>

         /// 生成Sec-WebSocket-Accept

         /// </summary>

         /// <param name="handShakeText">客户端握手信息</param>

         /// <returns>Sec-WebSocket-Accept</returns>

         private static string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength)

         {

             string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength);

             string key = string.Empty;

             Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");

             Match m = r.Match(handShakeText);

             if (m.Groups.Count != 0)

             {

                 key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();

             }

             byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));

             return Convert.ToBase64String(encryptionString);

         }



         /// <summary>

         /// 解析客户端数据包

         /// </summary>

         /// <param name="recBytes">服务器接收的数据包</param>

         /// <param name="recByteLength">有效数据长度</param>

         /// <returns></returns>

         private static string AnalyticData(byte[] recBytes, int recByteLength)

         {

             if (recByteLength < 2) { return string.Empty; }



             bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧  

             if (!fin)

             {

                 return string.Empty;// 超过一帧暂不处理 

             }



             bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码  

             if (!mask_flag)

             {

                 return string.Empty;// 不包含掩码的暂不处理

             }



             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]);

             }



             return Encoding.UTF8.GetString(payload_data);

         }





         /// <summary>

         /// 打包服务器数据

         /// </summary>

         /// <param name="message">数据</param>

         /// <returns>数据包</returns>

         private static byte[] PackData(string message)

         {

             byte[] contentBytes = null;

             byte[] temp = Encoding.UTF8.GetBytes(message);



             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

             {

                 // 暂不处理超长内容  

             }



             return contentBytes;

         }

     }

 }




标签:知识点,WebSocket,string,ws,html5,整理,Sec,byte,客户端
From: https://blog.51cto.com/u_13128132/6323331

相关文章

  • 【整理】html5知识点4
    1、==================================================================HTML5语义元素HTML5中新的语义元素许多现有网站都包含以下HTML代码:<divid="nav">,<divclass="header">,或者<divid="footer">,来指明导航链接,头部,以......
  • 【整理】jQuery知识点4
    ★★★=============================================================jQuery-AJAXAJAX是与服务器交换数据的技术,它在不重载全部页面的情况下,实现了对部分网页的更新。关于jQuery与AJAXjQuery提供多个与AJAX有关的方法。通过jQueryAJAX方法,您能够使用H......
  • 【整理】html5知识点3
    1、====================================================================HTML5新的Input类型HTML5拥有多个新的表单输入类型。这些新特性提供了更好的输入控制和验证。本章全面介绍这些新的输入类型:colordatedatetimedatetime-localemailmonthnu......
  • 【整理】html知识点
    1、链接target属性_blank在新窗口中打开<ahref="http://www.runoob.com/"target="_blank">访问菜鸟教程!</a>2、链接id属性在HTML文档中插入ID:<aid="tips">有用的提示部分</a>在HTML文档中创建一个链接到"有用的提示部分(id="tips......
  • 《操作系统》知识框架整理
    文章目录第1章计算机系统概述1.1操作系统的基本概念1.1.1操作系统的三大功能1.1.2操作系统的四大特征1.2操作系统的分类1.3操作系统的运行机制和体系结构1.3.1运行机制和体系结构1.3.2中断和异常1.3.3系统调用第2章进程管理2.1进程与线程2.1.1进程的定义、特征、组成......
  • c语言程序设计知识点总结03
    c语言程序设计知识点总结03地址(Address):计算机的内存由若干个字节内存单元构成,每个字节内存单元都有一个唯一的地址用于区分和存取单元中的数据。形式上,地址是一个无符号整数,从0开始,依次递增,在表达和交流时,通常把地址写成十六进制数。指针(Pointer):一个变量,它存有另外一......
  • WEB—漏洞必懂知识点
     CTF,SRC,红蓝对抗,实战等SRC:针对与网站上面的漏洞,进行提交漏洞并证实可以获得相应的佣金。偏向于实战,重点掌握获取网站权限 漏洞等级划分高危:SQL注入,文件上传,文件包含,代码执行,未授权访问——直接影响到网站权限和数据库权限,能够直接获取数据或者获取到一些敏感信息只要涉......
  • 2023上半年软考系统分析师科目一整理-01
    (2023上半年软考系统分析师科目一整理-01)1.面向对象面向对象分析中,对象是类的实例。对象的构成成分包含了(A),属性和方法(或操作)。A.标识 B.消息 C.规则 D.结构对象的三要素为:属性(数据)、方法(操作)、对象ID(标识)。面向对象分析中,类与类之间的“IS-A”关系的是一种(C),......
  • 基于 HTML5 WebGL 的垃圾分类系统
    前言垃圾分类,一般是指按一定规定或标准将垃圾分类储存、分类投放和分类搬运,从而转变成公共资源的一系列活动的总称。分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用。垃圾在分类储存阶段属于公众的私有品,垃圾经公众分类投放后成为公众所在小区或社区的区域性准公共资源,垃圾......
  • HTML5 + WebGL 实现的垃圾分类系统
    前言垃圾分类,一般是指按一定规定或标准将垃圾分类储存、分类投放和分类搬运,从而转变成公共资源的一系列活动的总称。分类的目的是提高垃圾的资源价值和经济价值,力争物尽其用。垃圾在分类储存阶段属于公众的私有品,垃圾经公众分类投放后成为公众所在小区或社区的区域性准公共资源,垃圾......