websocket原理
Posted woz333333
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了websocket原理相关的知识,希望对你有一定的参考价值。
内容:
1.websocket介绍
2.websocket原理
3.websocket实例
参考:https://www.cnblogs.com/jingmoxukong/p/7755643.html
1.websocket介绍
(1)什么是WebSocket
WebSocket 是一种网络通信协议。RFC6455 定义了它的通信标准。
WebSocket 是 html5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
另外基于多线程或多进程的服务器无法适用于 WebSockets,因为它旨在打开连接,尽可能快地处理请求,然后关闭连接。任何实际的 WebSockets 服务器端实现都需要一个异步服务器
(2)websocket的特点
- 双向
- 性能高
2.websocket原理
(1)websocket在服务端和客户端
在客户端,没有必要为 WebSockets 使用 javascript 库。实现 WebSockets 的 Web 浏览器将通过 WebSockets 对象公开所有必需的客户端功能(主要指支持 Html5 的浏览器)
而WebSocket 在服务端的实现非常丰富。Node.js、Java、C++、Python 等多种语言都有自己的解决方案
node中:
而Java 的 web 一般都依托于 servlet 容器(Tomcat、Jetty、Resin),此外Spring框架对 WebSocket 也提供了支持
(2)websocket核心原理
关于websocket:
- 建立在 TCP 协议之上,服务器端的实现比较容易。
- 与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
- 数据格式比较轻量,性能开销小,通信高效。
- 可以发送文本,也可以发送二进制数据。
- 没有同源限制,客户端可以与任意服务器通信。
- 协议标识符是
ws
(如果加密,则为wss
),服务器网址就是 URL
底层协议包装:
(3)HTTP 和 WebSocket 有什么关系?
Websocket 其实是一个新协议,跟 HTTP 协议基本没有关系,只是为了兼容现有浏览器的握手规范而已,也就是说它是 HTTP 协议上的一种补充
而HTTP2.0(未来推行,现在还未推行)中其实要实现全双工通信,故也有人说websocket最终将被HTTP2.0替代
(4)WebSocket属性
WebSocket是前台的东西,是HTML5带的一种东西:
- 只有前台有WebSocket这个东西
- 后台没有,后台有Socket
3.websocket实例
(1)原生websocket
虽然原生的websocket实现起来麻烦,写起来麻烦,但是我们还是要对其有所了解
1 原生WebSocket: 2 i.net模块 3 ii.流程 4 a.握手 5 C:version:13、sec-websocket-key:xxxxx、sha1(key+mask)=>base64 6 S:101 Switching Protocols、sec-websocket-accept: base64 7 C <-> S 8 9 Client: 10 onopen 11 onmessage 12 onclose 13 14 Server: 15 net.createServer(sock=>{}); 16 sock.once(\'data\', 握手); 17 sock.on(\'data\', 数据请求); 18 sock.on(\'end\'); 19 20 b.数据帧解析
原生websocket使用实例如下:
1 // 服务端 2 const http = require(\'http\'); // HTTP 非原生Socket 3 const net = require(\'net\'); // TCP 原生Socket 4 const crypto = require(\'crypto\'); 5 6 /* 7 let server=http.createServer((req, res)=>{ 8 console.log(\'连接\'); 9 }); 10 server.listen(8080); 11 */ 12 13 let server = net.createServer(sock => { 14 console.log(\'连接\'); 15 16 //数据过来 — 握手只有一次 17 sock.once(\'data\', function(data){ 18 console.log(\'hand shake start...\'); 19 20 // 下面都是解析HTTP头 21 let str = data.toString(); 22 let lines = str.split(\'\\r\\n\'); 23 24 //舍弃第一行和最后两行 25 lines = lines.slice(1, lines.length - 2); 26 //切开headers中的每一项key-value数据 27 let headers = {}; 28 lines.forEach(function(line) { 29 let [key, val] = line.split(\': \'); 30 headers[key.toLowerCase()] = val; 31 }); 32 console.log(headers); 33 34 if (headers[\'upgrade\'] !== \'websocket\') { 35 console.log(\'其他协议: \', headers[\'upgrade\']); 36 sock.end(); 37 } else if (headers[\'sec-websocket-version\'] !== \'13\') { 38 console.log(\'版本不对\', headers[\'sec-websocket-version\']); 39 sock.end(); 40 } else { 41 let key = headers[\'sec-websocket-key\']; 42 let mask = \'258EAFA5-E914-47DA-95CA-C5AB0DC85B11\'; 43 44 //sha1(key+mask)->base64=>client 45 let hash = crypto.createHash(\'sha1\'); 46 hash.update(key + mask); 47 let key2 = hash.digest(\'base64\'); 48 sock.write(`HTTP/1.1 101 Switching Protocols\\r\\nUpgrade: websocket\\r\\nConnection: Upgrade\\r\\nSec-WebSocket-Accept: ${key2}\\r\\n\\r\\n`); 49 50 console.log(\'hand shake end\'); 51 52 //真正的数据 53 sock.on(\'data\', data => { 54 console.log(\'有数据\'); 55 console.log(data); 56 }); 57 } 58 }); 59 60 //断开了 61 sock.on(\'end\', () => { 62 console.log(\'客户端已断开\'); 63 }); 64 }); 65 server.listen(8080);
1 // 客户端 2 <!DOCTYPE html> 3 <html> 4 <head> 5 <meta charset="utf-8"> 6 <title></title> 7 <script> 8 let sock=new WebSocket(\'ws://localhost:8080/\'); 9 10 // 原生websocket中没有sock.emit 自己用sock.send封装一个sock.emit: 11 sock.emit=function (name, ...args){ 12 alert(JSON.stringify({name, data: [...args]})); 13 sock.send(JSON.stringify({name, data: [...args]})); 14 }; 15 16 // 连上了 17 sock.onopen=function (){ 18 alert(\'连接上了\'); 19 20 sock.emit(\'msg\', 12, 5); 21 }; 22 23 // 有数据 24 sock.onmessage=function (){ 25 alert(\'有消息过来\'); 26 }; 27 28 // 断开了 29 sock.onclose=function (){ 30 alert(\'断了\'); 31 }; 32 </script> 33 </head> 34 <body> 35 36 </body> 37 </html>
(2)socket.io实现websocket
实现套路:
1 // 服务端: 2 const http = require(\'http\') 3 const io = require(\'socket.io\') 4 5 let httpServer = http.createServer(function (req, res) { 6 7 }) 8 httpServer.listen(8080) 9 10 let wsServer = io.listen(httpServer) 11 12 wsServer.on(\'connection\', function (sock) { 13 // sock.emit() --> 发送 14 // sock.on() --> 接收 15 // sock.on(\'connection\') --> 开始连接 16 // sock.on(\'disconnect\') --> 断开连接 17 })
1 // 客户端: 2 let sock = io.connect(\'ws://localhost:8080/\') 3 4 sock.emit() // 发送 5 sock.on() // 接收 6 sock.on(\'connect\') // 开始连接 7 sock.on(\'disconnect\') // 断开连接
(3)socket.io实现聊天室
1 // 前端代码: 2 <!-- author: wyb --> 3 <!DOCTYPE html> 4 <html lang="en"> 5 <head> 6 <meta charset="UTF-8"> 7 <meta name="viewport" content="width=device-width, initial-scale=1"> 8 <title>聊天室</title> 9 <style> 10 *{ 11 margin: 0; 12 padding: 0; 13 } 14 .container{ 15 width: 93%; 16 margin: 0 auto; 17 padding: 15px; 18 } 19 .err_box{ 20 width: 100%; 21 height: 20px; 22 line-height: 20px; 23 text-align: center; 24 color: red; 25 display: none; 26 } 27 #u1{ 28 width: 100%; 29 height: 360px; 30 border: 1px solid black; 31 overflow: auto; 32 margin: 15px 0; 33 } 34 #u1 li.me{ 35 color: green; 36 } 37 #form{ 38 width: 100%; 39 text-align: center; 40 margin: 15px 0; 41 } 42 #form textarea{ 43 width: 100%; 44 min-height: 130px; 45 margin: 10px 0; 46 } 47 </style> 48 <link rel="stylesheet" href="https://unpkg.com/purecss@1.0.0/build/pure-min.css" 49 integrity="sha384-nn4HPE8lTHyVtfCBi5yW9d20FjT8BJwUXyWZT9InLYax14RDjBj46LmSztkmNP9w" crossorigin="anonymous"> 50 <script src="http://localhost:8080/socket.io/socket.io.js"></script> 51 <script> 52 let sock = io.connect(\'ws://localhost:8080/\') 53 54 sock.on(\'connect\', function () { 55 console.log(\'已连接\') 56 document.querySelector(\'.err_box\').style.display = "none" 57 }) 58 sock.on(\'disconnect\', function () { 59 console.log(\'已断开\') 60 document.querySelector(\'.err_box\').style.display = "block" 61 }) 62 63 window.onload = function(){ 64 let oTxt = document.querySelector(\'#txt1\') 65 let oBtn = document.querySelector(\'#btn1\') 66 let oUl = document.querySelector(\'#u1\') 67 68 oBtn.onclick = function () { 69 sock.emit(\'msg\', oTxt.value) 70 71 // 把自己输入的信息添加到自己页面中并将颜色设置为绿色 72 let oLi = document.createElement(\'li\') 73 oLi.innerHTML = oTxt.value 74 oLi.className = \'me\' 75 76 oTxt.value = \'\' 77 oUl.appendChild(oLi) 78 } 79 80 sock.on(\'msg\', function (str) { 81 let oLi = document.createElement(\'li\') 82 oLi.innerHTML = str 83 oUl.appendChild(oLi) 84 }) 85 86 } 87 88 // 聊天室 89 // sock.emit() 90 // sock.on() 91 92 </script> 93 94 </head> 95 <body> 96 97 <div class="container"> 98 <div class="err_box">无法连接到服务器,请检查网络</div> 99 <ul id="u1"></ul> 100 <form class="pure-form" id="form"> 101 <textarea class="pure-input-1" id="txt1" name="" placeholder="请输入聊天内容"></textarea> <br> 102 <input type="button" value="发送" id="btn1" class="pure-button pure-button-primary"> 103 </form> 104 </div> 105 </body> 106 </html>